Access control tests

Add test cases for the join_access_control governance setting and for
the access control plugin check_create_ and check_remote_ hooks,
using a wrapper plugin that simulates failure for each of these,
to test the DDSI integration with the access control plugin.
This commit also contains fixes for:
- an assert on DDS_RETCODE_OK in dds_create_reader and
dds_create_writer that cased the application to terminate in case
creation of a reader or writer is not allowed by security
- do not match a proxy reader that has the 'relay_only' set to
true, which is currently unsupported

Signed-off-by: Dennis Potman <dennis.potman@adlinktech.com>
This commit is contained in:
Dennis Potman 2020-04-14 20:25:20 +02:00 committed by eboasson
parent 080514d45a
commit 19bc6f33cc
21 changed files with 1022 additions and 437 deletions

View file

@ -30,6 +30,7 @@
#include "dds__builtin.h"
#include "dds/ddsi/ddsi_sertopic.h"
#include "dds/ddsi/ddsi_entity_index.h"
#include "dds/ddsi/ddsi_security_omg.h"
DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader)
@ -430,6 +431,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
/* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null
argument, but that isn't the case here */
struct ddsi_domaingv *gv = &sub->m_entity.m_domain->gv;
rqos = dds_create_qos ();
if (qos)
ddsi_xqos_mergein_missing (rqos, qos, DDS_READER_QOS_MASK);
@ -437,25 +439,43 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
ddsi_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0);
if (tp->m_ktopic->qos)
ddsi_xqos_mergein_missing (rqos, tp->m_ktopic->qos, ~(uint64_t)0);
ddsi_xqos_mergein_missing (rqos, &sub->m_entity.m_domain->gv.default_xqos_rd, ~(uint64_t)0);
ddsi_xqos_mergein_missing (rqos, &gv->default_xqos_rd, ~(uint64_t)0);
if ((rc = ddsi_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) < 0 ||
(rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK)
{
dds_delete_qos (rqos);
if ((rc = ddsi_xqos_valid (&gv->logconfig, rqos)) < 0 || (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK)
goto err_bad_qos;
}
/* Additional checks required for built-in topics: we don't want to
run into a resource limit on a built-in topic, it is a needless
complication */
if (pseudo_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, pseudo_topic, rqos))
{
dds_delete_qos (rqos);
rc = DDS_RETCODE_INCONSISTENT_POLICY;
goto err_bad_qos;
}
thread_state_awake (lookup_thread_state (), gv);
const struct ddsi_guid * ppguid = dds_entity_participant_guid (&sub->m_entity);
struct participant * pp = entidx_lookup_participant_guid (gv->entity_index, ppguid);
if (pp == NULL)
{
GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid));
rc = DDS_RETCODE_BAD_PARAMETER;
goto err_pp_not_found;
}
#ifdef DDSI_INCLUDE_SECURITY
/* Check if DDS Security is enabled */
if (q_omg_participant_is_secure (pp))
{
/* ask to access control security plugin for create reader permissions */
if (!q_omg_security_check_create_reader (pp, gv->config.domainId, tp->m_stopic->name, rqos))
{
rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
goto err_not_allowed;
}
}
#endif
/* Create reader and associated read cache (if not provided by caller) */
struct dds_reader * const rd = dds_alloc (sizeof (*rd));
const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK);
@ -474,8 +494,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
it; and then invoke those listeners that are in the pending set */
dds_entity_init_complete (&rd->m_entity);
thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv);
rc = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, dds_entity_participant_guid (&sub->m_entity), tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
rc = new_reader (&rd->m_rd, &rd->m_entity.m_guid, NULL, pp, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd);
assert (rc == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */
thread_state_asleep (lookup_thread_state ());
@ -487,7 +506,13 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe
dds_subscriber_unlock (sub);
return reader;
#ifdef DDSI_INCLUDE_SECURITY
err_not_allowed:
#endif
err_pp_not_found:
thread_state_asleep (lookup_thread_state ());
err_bad_qos:
dds_delete_qos (rqos);
dds_topic_allow_set_qos (tp);
err_pp_mismatch:
dds_topic_unpin (tp);

View file

@ -20,6 +20,7 @@
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_xmsg.h"
#include "dds/ddsi/ddsi_entity_index.h"
#include "dds/ddsi/ddsi_security_omg.h"
#include "dds__writer.h"
#include "dds__listener.h"
#include "dds__init.h"
@ -312,6 +313,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
dds_topic_defer_set_qos (tp);
/* Merge Topic & Publisher qos */
struct ddsi_domaingv *gv = &pub->m_entity.m_domain->gv;
wqos = dds_create_qos ();
if (qos)
ddsi_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK);
@ -319,29 +321,47 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
ddsi_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0);
if (tp->m_ktopic->qos)
ddsi_xqos_mergein_missing (wqos, tp->m_ktopic->qos, ~(uint64_t)0);
ddsi_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0);
ddsi_xqos_mergein_missing (wqos, &gv->default_xqos_wr, ~(uint64_t)0);
if ((rc = ddsi_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 ||
(rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK)
{
dds_delete_qos(wqos);
if ((rc = ddsi_xqos_valid (&gv->logconfig, wqos)) < 0 || (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK)
goto err_bad_qos;
thread_state_awake (lookup_thread_state (), gv);
const struct ddsi_guid *ppguid = dds_entity_participant_guid (&pub->m_entity);
struct participant *pp = entidx_lookup_participant_guid (gv->entity_index, ppguid);
if (pp == NULL)
{
GVLOGDISC ("new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid));
rc = DDS_RETCODE_BAD_PARAMETER;
goto err_pp_not_found;
}
#ifdef DDSI_INCLUDE_SECURITY
/* Check if DDS Security is enabled */
if (q_omg_participant_is_secure (pp))
{
/* ask to access control security plugin for create writer permissions */
if (!q_omg_security_check_create_writer (pp, gv->config.domainId, tp->m_stopic->name, wqos))
{
rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
goto err_not_allowed;
}
}
#endif
/* Create writer */
ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.xmit_conn;
ddsi_tran_conn_t conn = gv->xmit_conn;
struct dds_writer * const wr = dds_alloc (sizeof (*wr));
const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK);
wr->m_topic = tp;
dds_entity_add_ref_locked (&tp->m_entity);
wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), pub->m_entity.m_domain->gv.config.xpack_send_async);
wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), gv->config.xpack_send_async);
wrinfo = whc_make_wrinfo (wr, wqos);
wr->m_whc = whc_new (&pub->m_entity.m_domain->gv, wrinfo);
wr->m_whc = whc_new (gv, wrinfo);
whc_free_wrinfo (wrinfo);
wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch;
wr->whc_batch = gv->config.whc_batch;
thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv);
rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, dds_entity_participant_guid (&pub->m_entity), tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
rc = new_writer (&wr->m_wr, &wr->m_entity.m_guid, NULL, pp, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr);
assert(rc == DDS_RETCODE_OK);
thread_state_asleep (lookup_thread_state ());
@ -355,7 +375,13 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit
dds_publisher_unlock (pub);
return writer;
#ifdef DDSI_INCLUDE_SECURITY
err_not_allowed:
#endif
err_pp_not_found:
thread_state_asleep (lookup_thread_state ());
err_bad_qos:
dds_delete_qos(wqos);
dds_topic_allow_set_qos (tp);
err_pp_mismatch:
dds_topic_unpin (tp);

View file

@ -22,64 +22,37 @@ extern "C" {
#endif
void g_omg_shallow_copy_StringSeq(DDS_Security_StringSeq *dst, const ddsi_stringseq_t *src);
void g_omg_shallow_free_StringSeq(DDS_Security_StringSeq *obj);
void q_omg_copy_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src);
void q_omg_shallow_copyin_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src);
void q_omg_shallow_copyout_PropertySeq(dds_propertyseq_t *dst, const DDS_Security_PropertySeq *src);
void q_omg_shallow_free_PropertySeq(DDS_Security_PropertySeq *obj);
void q_omg_shallow_copyin_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *dst, const dds_binarypropertyseq_t *src);
void q_omg_shallow_copyout_BinaryPropertySeq(dds_binarypropertyseq_t *dst, const DDS_Security_BinaryPropertySeq *src);
void q_omg_shallow_free_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *obj);
void q_omg_shallow_copy_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *dst, const dds_property_qospolicy_t *src);
void q_omg_shallow_copy_security_qos(DDS_Security_Qos *dst, const struct dds_qos *src);
void q_omg_shallow_free_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *obj);
void q_omg_shallow_free_security_qos(DDS_Security_Qos *obj);
void q_omg_security_dataholder_copyin(nn_dataholder_t *dh, const DDS_Security_DataHolder *holder);
void q_omg_security_dataholder_copyout(DDS_Security_DataHolder *holder, const nn_dataholder_t *dh);
void q_omg_shallow_copyin_DataHolder(DDS_Security_DataHolder *dst, const nn_dataholder_t *src);
void q_omg_shallow_copyout_DataHolder(nn_dataholder_t *dst, const DDS_Security_DataHolder *src);
void q_omg_shallow_free_DataHolder(DDS_Security_DataHolder *obj);
void q_omg_shallow_free_nn_dataholder(nn_dataholder_t *holder);
void q_omg_shallow_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src);
void q_omg_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src);
void q_omg_shallow_copyout_DataHolderSeq(nn_dataholderseq_t *dst, const DDS_Security_DataHolderSeq *src);
void q_omg_shallow_free_DataHolderSeq(DDS_Security_DataHolderSeq *obj);
void q_omg_shallow_free_nn_dataholderseq(nn_dataholderseq_t *obj);
void q_omg_shallow_copy_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const ddsi_plist_t *plist);
void q_omg_shallow_free_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *obj);
void q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo);
void q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *obj);
void q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo);
void q_omg_shallow_free_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *obj);
void q_omg_shallow_copy_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *dst, const char *topic_name, const char *type_name);
void q_omg_shallow_free_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *obj);
#if defined (__cplusplus)
}

View file

@ -642,9 +642,8 @@ DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsi
GUID "ppguid". May return NULL if participant unknown or
writer/reader already known. */
dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_reader (struct reader **rd_out, struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg);
dds_return_t new_reader (struct reader **rd_out, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg);
void update_reader_qos (struct reader *rd, const struct dds_qos *xqos);
void update_writer_qos (struct writer *wr, const struct dds_qos *xqos);

View file

@ -2136,7 +2136,8 @@ bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *p
struct dds_security_context *sc = q_omg_security_get_secure_context(pp);
DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT;
DDS_Security_PublicationBuiltinTopicDataSecure publication_data;
bool ok = true;
DDS_Security_TopicBuiltinTopicData topic_data;
bool result = true;
if (!sc)
return true;
@ -2167,19 +2168,32 @@ bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *p
else
{
q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(&publication_data, &pwr->e.guid, pwr->c.xqos, &pwr->c.security_info);
ok = sc->access_control_context->check_remote_datawriter(sc->access_control_context, permissions_handle, (int)domain_id, &publication_data, &exception);
q_omg_shallow_free_PublicationBuiltinTopicDataSecure(&publication_data);
if (!ok)
result = sc->access_control_context->check_remote_datawriter(sc->access_control_context, permissions_handle, (int)domain_id, &publication_data, &exception);
if (!result)
{
if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, publication_data.topic_name))
EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote writer "PGUIDFMT": %s", PGUID(pwr->e.guid));
else
DDS_Security_Exception_reset(&exception);
}
else
{
q_omg_shallow_copy_TopicBuiltinTopicData(&topic_data, publication_data.topic_name, publication_data.type_name);
result = sc->access_control_context->check_remote_topic(sc->access_control_context, permissions_handle, (int)domain_id, &topic_data, &exception);
q_omg_shallow_free_TopicBuiltinTopicData(&topic_data);
if (!result)
{
if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, publication_data.topic_name))
EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote topic %s: %s", publication_data.topic_name);
else
DDS_Security_Exception_reset(&exception);
}
}
q_omg_shallow_free_PublicationBuiltinTopicDataSecure(&publication_data);
}
}
return ok;
return result;
}
static void send_reader_crypto_tokens(struct reader *rd, struct proxy_writer *pwr, DDS_Security_DatareaderCryptoHandle local_crypto, DDS_Security_DatawriterCryptoHandle remote_crypto)
@ -2363,7 +2377,10 @@ bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *p
struct ddsi_domaingv *gv = pp->e.gv;
struct dds_security_context *sc = q_omg_security_get_secure_context(pp);
DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT;
bool ok = true;
DDS_Security_SubscriptionBuiltinTopicDataSecure subscription_data;
DDS_Security_TopicBuiltinTopicData topic_data;
DDS_Security_boolean sec_relay_only;
bool result = true;
/* relay_only is meaningless in all cases except the one where the access control plugin says otherwise */
*relay_only = false;
@ -2396,25 +2413,34 @@ bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *p
}
else
{
DDS_Security_SubscriptionBuiltinTopicDataSecure subscription_data;
DDS_Security_boolean sec_relay_only;
q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(&subscription_data, &prd->e.guid, prd->c.xqos, &prd->c.security_info);
ok = sc->access_control_context->check_remote_datareader(sc->access_control_context, permissions_handle, (int)domain_id, &subscription_data, &sec_relay_only, &exception);
q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(&subscription_data);
if (ok)
*relay_only = !!sec_relay_only;
else
result = sc->access_control_context->check_remote_datareader(sc->access_control_context, permissions_handle, (int)domain_id, &subscription_data, &sec_relay_only, &exception);
if (!result)
{
if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, subscription_data.topic_name))
EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote reader "PGUIDFMT": %s", PGUID(prd->e.guid));
else
DDS_Security_Exception_reset(&exception);
}
else
{
*relay_only = !!sec_relay_only;
q_omg_shallow_copy_TopicBuiltinTopicData(&topic_data, subscription_data.topic_name, subscription_data.type_name);
result = sc->access_control_context->check_remote_topic(sc->access_control_context, permissions_handle, (int)domain_id, &topic_data, &exception);
q_omg_shallow_free_TopicBuiltinTopicData(&topic_data);
if (!result)
{
if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, subscription_data.topic_name))
EXCEPTION_ERROR(gv, &exception, "Access control does not allow remote topic %s: %s", subscription_data.topic_name);
else
DDS_Security_Exception_reset(&exception);
}
}
q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(&subscription_data);
}
}
return ok;
return result;
}
void q_omg_get_proxy_endpoint_security_info(const struct entity_common *entity, nn_security_info_t *proxypp_sec_info, const ddsi_plist_t *plist, nn_security_info_t *info)

View file

@ -703,6 +703,24 @@ q_omg_shallow_free_PublicationBuiltinTopicDataSecure(
g_omg_shallow_free_StringSeq(&obj->partition.name);
}
void
q_omg_shallow_copy_TopicBuiltinTopicData(
DDS_Security_TopicBuiltinTopicData *dst,
const char *topic_name,
const char *type_name)
{
memset(dst, 0, sizeof(DDS_Security_TopicBuiltinTopicData));
dst->name = (DDS_Security_string)topic_name;
dst->type_name = (DDS_Security_string)type_name;
}
void
q_omg_shallow_free_TopicBuiltinTopicData(
DDS_Security_TopicBuiltinTopicData *obj)
{
DDSRT_UNUSED_ARG(obj);
}
#endif /* DDSI_INCLUDE_SECURITY */

View file

@ -2771,6 +2771,7 @@ void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_wri
static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_reader *prd, ddsrt_mtime_t tnow)
{
struct ddsi_domaingv *gv = wr->e.gv;
const int isb0 = (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0);
const int isb1 = (is_builtin_entityid (prd->e.guid.entityid, prd->c.vendor) != 0);
dds_qos_policy_id_t reason;
@ -2790,13 +2791,15 @@ static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_re
if (!q_omg_security_check_remote_reader_permissions (prd, wr->e.gv->config.domainId, wr->c.pp, &relay_only))
{
EELOGDISC (&wr->e, "connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") not allowed by security\n",
PGUID (wr->e.guid), PGUID (prd->e.guid));
GVLOGDISC ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") not allowed by security\n", PGUID (wr->e.guid), PGUID (prd->e.guid));
}
else if (relay_only)
{
GVWARNING ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") relay_only not supported\n", PGUID (wr->e.guid), PGUID (prd->e.guid));
}
else if (!q_omg_security_match_remote_reader_enabled (wr, prd, relay_only, &crypto_handle))
{
EELOGDISC (&wr->e, "connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") waiting for approval by security\n",
PGUID (wr->e.guid), PGUID (prd->e.guid));
GVLOGDISC ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") waiting for approval by security\n", PGUID (wr->e.guid), PGUID (prd->e.guid));
}
else
{
@ -3801,28 +3804,11 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g
return 0;
}
dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg)
dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg)
{
struct participant *pp;
dds_return_t rc;
uint32_t kind;
if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL)
{
GVLOGDISC ("new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid));
return DDS_RETCODE_BAD_PARAMETER;
}
#ifdef DDSI_INCLUDE_SECURITY
/* Check if DDS Security is enabled */
if (q_omg_participant_is_secure (pp))
{
/* ask to access control security plugin for create writer permissions */
if (!q_omg_security_check_create_writer (pp, gv->config.domainId, topic->name, xqos))
return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
}
#endif
/* participant can't be freed while we're mucking around cos we are
awake and do not touch the thread's vtime (entidx_lookup already
verifies we're awake) */
@ -4367,10 +4353,9 @@ static dds_return_t new_reader_guid
dds_return_t new_reader
(
struct reader **rd_out,
struct ddsi_domaingv *gv,
struct ddsi_guid *rdguid,
const struct ddsi_guid *group_guid,
const struct ddsi_guid *ppguid,
struct participant *pp,
const struct ddsi_sertopic *topic,
const struct dds_qos *xqos,
struct ddsi_rhc * rhc,
@ -4378,26 +4363,9 @@ dds_return_t new_reader
void * status_cbarg
)
{
struct participant * pp;
dds_return_t rc;
uint32_t kind;
if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL)
{
GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid));
return DDS_RETCODE_BAD_PARAMETER;
}
#ifdef DDSI_INCLUDE_SECURITY
/* Check if DDS Security is enabled */
if (q_omg_participant_is_secure (pp))
{
/* ask to access control security plugin for create writer permissions */
if (!q_omg_security_check_create_reader (pp, gv->config.domainId, topic->name, xqos))
return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY;
}
#endif
rdguid->prefix = pp->e.guid.prefix;
kind = topic->topickind_no_key ? NN_ENTITYID_KIND_READER_NO_KEY : NN_ENTITYID_KIND_READER_WITH_KEY;
if ((rc = pp_allocate_entityid (&rdguid->entityid, kind, pp)) < 0)

View file

@ -68,7 +68,7 @@ set(security_core_test_sources
)
if(ENABLE_SSL)
add_wrapper(access_control "")
add_wrapper(access_control dds_security_ac)
add_wrapper(authentication dds_security_auth)
add_wrapper(cryptography dds_security_crypto)
@ -108,7 +108,7 @@ configure_file("common/config_env.h.in" "common/config_env.h")
target_link_libraries(cunit_security_core PRIVATE ddsc security_api SecurityCoreTests)
if(ENABLE_SSL)
target_link_libraries(cunit_security_core PRIVATE dds_security_auth dds_security_ac dds_security_crypto dds_security_authentication_wrapper dds_security_cryptography_wrapper)
target_link_libraries(cunit_security_core PRIVATE dds_security_auth dds_security_ac dds_security_crypto dds_security_access_control_wrapper dds_security_authentication_wrapper dds_security_cryptography_wrapper)
target_link_libraries(cunit_security_core PRIVATE OpenSSL::SSL)
endif()
target_include_directories(cunit_security_core PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")

View file

@ -47,13 +47,13 @@ static const char *config =
" </Discovery>"
" <DDSSecurity>"
" <Authentication>"
" <Library finalizeFunction=\"finalize_authentication\" initFunction=\"init_authentication\"/>"
" <Library finalizeFunction=\"finalize_test_authentication_wrapped\" initFunction=\"init_test_authentication_wrapped\" path=\"" WRAPPERLIB_PATH("dds_security_authentication_wrapper") "\"/>"
" <IdentityCertificate>data:,${TEST_IDENTITY_CERTIFICATE}</IdentityCertificate>"
" <PrivateKey>data:,${TEST_IDENTITY_PRIVATE_KEY}</PrivateKey>"
" <IdentityCA>data:,${TEST_IDENTITY_CA_CERTIFICATE}</IdentityCA>"
" </Authentication>"
" <AccessControl>"
" <Library finalizeFunction=\"finalize_access_control\" initFunction=\"init_access_control\"/>"
" <Library initFunction=\"${ACCESS_CONTROL_INIT:-init_test_access_control_wrapped}\" finalizeFunction=\"${ACCESS_CONTROL_FINI:-finalize_test_access_control_wrapped}\" path=\"" WRAPPERLIB_PATH("dds_security_access_control_wrapper") "\"/>"
" ${INCL_GOV:+<Governance><![CDATA[}${TEST_GOVERNANCE}${INCL_GOV:+]]></Governance>}"
" ${INCL_PERM_CA:+<PermissionsCA>}${TEST_PERMISSIONS_CA}${INCL_PERM_CA:+</PermissionsCA>}"
" ${INCL_PERM:+<Permissions><![CDATA[}${TEST_PERMISSIONS}${INCL_PERM:+]]></Permissions>}"
@ -65,19 +65,22 @@ static const char *config =
"</Domain>";
#define MAX_DOMAINS 10
#define DDS_DOMAINID
#define DDS_DOMAINID 0
#define PF_F "file:"
#define PF_D "data:,"
static dds_entity_t g_domain[MAX_DOMAINS];
static dds_entity_t g_participant[MAX_DOMAINS];
static dds_entity_t g_pubsub[MAX_DOMAINS];
static dds_entity_t g_topic[MAX_DOMAINS];
static uint32_t g_topic_nr = 0;
static void access_control_init(
const char * id_certs[], const char * id_keys[], const char * id_ca[], bool exp_pp_fail[], size_t n_nodes,
bool incl_gov, const char * gov,
bool incl_perm, const char * perm,
bool incl_ca, const char * ca)
size_t n_nodes,
const char * id_certs[], const char * id_keys[], const char * id_ca[], bool exp_pp_fail[],
const char * ac_init_fns[], const char * ac_fini_fns[],
bool incl_gov[], const char * gov[],
bool incl_perm[], const char * perm[],
bool incl_ca[], const char * ca[])
{
CU_ASSERT_FATAL (n_nodes <= MAX_DOMAINS);
for (size_t i = 0; i < n_nodes; i++)
@ -86,12 +89,14 @@ static void access_control_init(
{ "TEST_IDENTITY_CERTIFICATE", id_certs[i], 1 },
{ "TEST_IDENTITY_PRIVATE_KEY", id_keys[i], 1 },
{ "TEST_IDENTITY_CA_CERTIFICATE", id_ca[i], 1 },
{ "INCL_GOV", incl_gov ? "1" : "", 2 },
{ "INCL_PERM", incl_perm ? "1" : "", 2 },
{ "INCL_PERM_CA", incl_ca ? "1" : "", 2 },
{ "TEST_GOVERNANCE", gov, 1 },
{ "TEST_PERMISSIONS", perm, 1 },
{ "TEST_PERMISSIONS_CA", ca, 1 },
{ "ACCESS_CONTROL_INIT", ac_init_fns ? ac_init_fns[i] : NULL, 1 },
{ "ACCESS_CONTROL_FINI", ac_fini_fns ? ac_fini_fns[i] : NULL, 1 },
{ "INCL_GOV", incl_gov[i] ? "1" : "", 2 },
{ "INCL_PERM", incl_perm[i] ? "1" : "", 2 },
{ "INCL_PERM_CA", incl_ca[i] ? "1" : "", 2 },
{ "TEST_GOVERNANCE", gov[i], 1 },
{ "TEST_PERMISSIONS", perm[i], 1 },
{ "TEST_PERMISSIONS_CA", ca[i], 1 },
{ NULL, NULL, 0 }
};
char *conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars);
@ -109,9 +114,6 @@ static void access_control_fini(size_t n)
CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain[i]), DDS_RETCODE_OK);
}
#define PF_F "file:"
#define PF_D "data:,"
#define GOV_F PF_F COMMON_ETC_PATH("default_governance.p7s")
#define GOV_FNE PF_F COMMON_ETC_PATH("default_governance_non_existing.p7s")
#define GOV_DI PF_D COMMON_ETC_PATH("default_governance.p7s")
@ -149,14 +151,18 @@ CU_Theory((const char * test_descr, const char * gov, const char * perm, const c
ddssec_access_control, config_parameters_file)
{
print_test_msg ("running test config_parameters_file: %s\n", test_descr);
bool has_gov = incl_empty_els || strlen (gov);
bool has_perm = incl_empty_els || strlen (perm);
bool has_ca = incl_empty_els || strlen (ca);
access_control_init (
2,
(const char *[]) { TEST_IDENTITY1_CERTIFICATE, TEST_IDENTITY1_CERTIFICATE },
(const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY },
(const char *[]) { TEST_IDENTITY_CA1_CERTIFICATE, TEST_IDENTITY_CA1_CERTIFICATE },
(bool []) { exp_fail, exp_fail }, 2,
incl_empty_els || strlen (gov), gov,
incl_empty_els || strlen (perm), perm,
incl_empty_els || strlen (ca), ca);
(bool []) { exp_fail, exp_fail }, NULL, NULL,
(bool []) { has_gov, has_gov }, (const char *[]) { gov, gov },
(bool []) { has_perm, has_perm }, (const char *[]) { perm, perm },
(bool []) { has_ca, has_ca }, (const char *[]) { ca, ca });
access_control_fini (2);
}
@ -170,8 +176,8 @@ CU_TheoryDataPoints(ddssec_access_control, permissions_expiry) = {
/* | */"valid -1 minute until now",
/* | | */"1s valid, create pp after 1100ms",
/* | | | */"node 2 permissions expired",
/* | | | | */"node 1 3s valid, write/read for 10s",
/* | | | | | */"node 2 3s valid, write/read for 10s"),
/* | | | | */"node 1 4s valid, write/read for 10s",
/* | | | | | */"node 2 4s valid, write/read for 10s"),
CU_DataPoints(int32_t, 0, -M(1), 0, 0, 0, 0), /* node 1 permissions not before (offset from local time) */
CU_DataPoints(int32_t, M(1), 0, S(1), D(1), S(4), D(1)), /* node 1 permissions not after (offset from local time) */
CU_DataPoints(int32_t, 0, -M(1), 0, -D(1), 0, 0), /* node 2 permissions not before (offset from local time) */
@ -182,11 +188,15 @@ CU_TheoryDataPoints(ddssec_access_control, permissions_expiry) = {
CU_DataPoints(uint32_t, 1, 0, 0, 0, 10000, 10000), /* write/read data during x ms */
CU_DataPoints(bool, false, false, false, false, true, true), /* expect read data failure */
};
#undef S
#undef D
#undef H
#undef M
CU_Theory(
(const char * test_descr,
int32_t perm1_not_before, int32_t perm1_not_after, int32_t perm2_not_before, int32_t perm2_not_after,
uint32_t delay_perm, bool exp_pp1_fail, bool exp_pp2_fail, uint32_t write_read_dur, bool exp_read_fail),
ddssec_access_control, permissions_expiry, .timeout=20)
ddssec_access_control, permissions_expiry, .timeout=30)
{
print_test_msg ("running test permissions_expiry: %s\n", test_descr);
@ -195,32 +205,38 @@ CU_Theory(
/* create ca and id1/id2 certs that will not expire during this test */
char *ca, *id1, *id2, *id1_subj, *id2_subj;
ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, D(1));
id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, D(1), &id1_subj);
id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, D(1), &id2_subj);
ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600);
id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj);
id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj);
/* localtime will be converted to gmtime in get_permissions_grant */
dds_time_t now = dds_time ();
char * perm_topic = get_permissions_topic (topic_name);
char * grants[] = {
get_permissions_grant ("id1", id1_subj, now + DDS_SECS(perm1_not_before), now + DDS_SECS(perm1_not_after), perm_topic, perm_topic, NULL),
get_permissions_grant ("id2", id2_subj, now + DDS_SECS(perm2_not_before), now + DDS_SECS(perm2_not_after), perm_topic, perm_topic, NULL) };
get_permissions_grant ("id1", id1_subj, NULL, now + DDS_SECS(perm1_not_before), now + DDS_SECS(perm1_not_after), perm_topic, perm_topic, NULL),
get_permissions_grant ("id2", id2_subj, NULL, now + DDS_SECS(perm2_not_before), now + DDS_SECS(perm2_not_after), perm_topic, perm_topic, NULL) };
char * perm_config = get_permissions_config (grants, 2, true);
dds_sleepfor (DDS_MSECS (delay_perm));
const char * def_gov = PF_F COMMON_ETC_PATH("default_governance.p7s");
const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem");
access_control_init (
2,
(const char *[]) { id1, id2 },
(const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY },
(const char *[]) { ca, ca },
(bool []) { exp_pp1_fail, exp_pp2_fail }, 2,
true, PF_F COMMON_ETC_PATH("default_governance.p7s"),
true, perm_config,
true, PF_F COMMON_ETC_PATH("default_permissions_ca.pem"));
(bool []) { exp_pp1_fail, exp_pp2_fail }, NULL, NULL,
(bool []) { true, true }, (const char *[]) { def_gov, def_gov },
(bool []) { true, true }, (const char *[]) { perm_config, perm_config },
(bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca });
if (write_read_dur > 0)
{
dds_entity_t wr = 0, rd = 0;
rd_wr_init (g_participant[0], &g_pubsub[0], &g_topic[0], &wr, g_participant[1], &g_pubsub[1], &g_topic[1], &rd, topic_name);
dds_entity_t pub, sub;
dds_entity_t topic0, topic1;
rd_wr_init (g_participant[0], &pub, &topic0, &wr, g_participant[1], &sub, &topic1, &rd, topic_name);
sync_writer_to_readers(g_participant[0], wr, 1);
write_read_for (wr, g_participant[1], rd, DDS_MSECS (write_read_dur), false, exp_read_fail);
}
@ -236,9 +252,6 @@ CU_Theory(
ddsrt_free (id1);
ddsrt_free (id2);
}
#undef D
#undef H
#undef M
#define N_RD 1 // N_RD > 1 not yet implemented
@ -256,9 +269,10 @@ CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20)
// 1st node used as reader, other nodes as writer
print_test_msg ("creating permissions grants\n");
const char *id[N_NODES], *pk[N_NODES], *ca_list[N_NODES];
const char *id[N_NODES], *pk[N_NODES], *ca_list[N_NODES], *gov[N_NODES], *perm_conf[N_NODES], *perm_ca[N_NODES];
char * id_subj[N_NODES], *grants[N_NODES];
bool exp_fail[N_NODES];
bool exp_fail[N_NODES], incl_el[N_NODES];
for (int i = 0; i < N_NODES; i++)
{
char *id_name;
@ -267,20 +281,25 @@ CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20)
ca_list[i] = ca;
id[i] = generate_identity (ca_list[i], TEST_IDENTITY_CA1_PRIVATE_KEY, id_name, pk[i], 0, 3600, &id_subj[i]);
exp_fail[i] = false;
gov[i] = PF_F COMMON_ETC_PATH ("default_governance.p7s");
perm_ca[i] = PF_F COMMON_ETC_PATH ("default_permissions_ca.pem");
incl_el[i] = true;
dds_duration_t v = DDS_SECS(i < N_RD ? 3600 : PERM_EXP_BASE + 2 * i); /* readers should not expire */
dds_time_t t_exp = ddsrt_time_add_duration (t_perm, v);
if (i >= N_RD)
print_test_msg ("w[%d] grant expires at %d.%06d\n", i - N_RD, (int32_t) (t_exp / DDS_NSECS_IN_SEC), (int32_t) (t_exp % DDS_NSECS_IN_SEC) / 1000);
grants[i] = get_permissions_grant (id_name, id_subj[i], t_perm, t_exp, perm_topic, perm_topic, NULL);
grants[i] = get_permissions_grant (id_name, id_subj[i], NULL, t_perm, t_exp, perm_topic, perm_topic, NULL);
ddsrt_free (id_name);
}
char * perm_config = get_permissions_config (grants, N_NODES, true);
char * perm_config_str = get_permissions_config (grants, N_NODES, true);
for (int i = 0; i < N_NODES; i++)
perm_conf[i] = perm_config_str;
access_control_init (
id, pk, ca_list, exp_fail, N_NODES,
true, PF_F COMMON_ETC_PATH ("default_governance.p7s"),
true, perm_config,
true, PF_F COMMON_ETC_PATH ("default_permissions_ca.pem"));
N_NODES,
id, pk, ca_list, exp_fail, NULL, NULL,
incl_el, gov, incl_el, perm_conf, incl_el, perm_ca);
dds_qos_t * qos = dds_create_qos ();
CU_ASSERT_FATAL (qos != NULL);
@ -374,6 +393,156 @@ CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20)
}
ddsrt_free (ca);
ddsrt_free (perm_topic);
ddsrt_free (perm_config);
ddsrt_free (perm_config_str);
}
#undef N_RD
#undef N_WR
#undef N_NODES
#undef PERM_EXP_BASE
#define na false
CU_TheoryDataPoints(ddssec_access_control, hooks) = {
CU_DataPoints(const char *,
/* */"init_test_access_control_local_participant_not_allowed",
/* | */"init_test_access_control_local_topic_not_allowed",
/* | | */"init_test_access_control_local_publishing_not_allowed",
/* | | | */"init_test_access_control_local_subscribing_not_allowed",
/* | | | | */"init_test_access_control_remote_permissions_invalidate",
/* | | | | | */"init_test_access_control_remote_participant_not_allowed",
/* | | | | | | */"init_test_access_control_remote_topic_not_allowed",
/* | | | | | | | */"init_test_access_control_remote_writer_not_allowed",
/* | | | | | | | | */"init_test_access_control_remote_reader_not_allowed",
/* | | | | | | | | | */"init_test_access_control_remote_reader_relay_only"),
CU_DataPoints(bool, true, false, false, false, false, false, false, false, false, false), // exp_pp_fail
CU_DataPoints(bool, na, true, false, false, false, false, false, false, false, false), // exp_local_topic_fail
CU_DataPoints(bool, na, false, false, false, false, false, false, false, false, false), // exp_remote_topic_fail
CU_DataPoints(bool, na, na, true, false, false, false, false, false, false, false), // exp_wr_fail
CU_DataPoints(bool, na, na, false, true, false, false, false, false, false, false), // exp_rd_fail
CU_DataPoints(bool, na, na, na, na, true, true, true, false, true, true), // exp_wr_rd_sync_fail
CU_DataPoints(bool, na, na, false, na, true, true, true, true, false, false), // exp_rd_wr_sync_fail
};
#undef na
CU_Theory(
(const char * init_fn, bool exp_pp_fail, bool exp_local_topic_fail, bool exp_remote_topic_fail, bool exp_wr_fail, bool exp_rd_fail, bool exp_wr_rd_sync_fail, bool exp_rd_wr_sync_fail),
ddssec_access_control, hooks, .timeout=40)
{
print_test_msg ("running test access_control_hooks: %s\n", init_fn);
const char * def_gov = PF_F COMMON_ETC_PATH("default_governance.p7s");
const char * def_perm = PF_F COMMON_ETC_PATH("default_permissions.p7s");
const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem");
access_control_init (
2,
(const char *[]) { TEST_IDENTITY1_CERTIFICATE, TEST_IDENTITY1_CERTIFICATE },
(const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY },
(const char *[]) { TEST_IDENTITY_CA1_CERTIFICATE, TEST_IDENTITY_CA1_CERTIFICATE },
(bool []) { exp_pp_fail, false },
(const char *[]) { init_fn, "init_test_access_control_wrapped" }, (const char *[]) { "finalize_test_access_control_not_allowed", "finalize_test_access_control_wrapped" },
(bool []) { true, true, true }, (const char *[]) { def_gov, def_gov },
(bool []) { true, true, true }, (const char *[]) { def_perm, def_perm },
(bool []) { true, true, true }, (const char *[]) { def_perm_ca, def_perm_ca });
if (!exp_pp_fail)
{
dds_entity_t lwr = 0, rwr = 0, lrd = 0, rrd = 0;
dds_entity_t ltopic[2], rtopic[2];
dds_entity_t lpub, lsub, rpub, rsub;
char topic_name[100];
// Local writer, remote reader
create_topic_name (AC_WRAPPER_TOPIC_PREFIX, g_topic_nr++, topic_name, sizeof (topic_name));
rd_wr_init_fail (
g_participant[0], &lpub, &ltopic[0], &lwr,
g_participant[1], &rsub, &rtopic[0], &rrd,
topic_name, exp_local_topic_fail, exp_wr_fail, exp_remote_topic_fail, false);
if (!exp_local_topic_fail && !exp_remote_topic_fail && !exp_wr_fail)
sync_writer_to_readers (g_participant[0], lwr, exp_wr_rd_sync_fail ? 0 : 1);
// Local reader, remote writer
create_topic_name (AC_WRAPPER_TOPIC_PREFIX, g_topic_nr++, topic_name, sizeof (topic_name));
rd_wr_init_fail (
g_participant[1], &rpub, &rtopic[1], &rwr,
g_participant[0], &lsub, &ltopic[1], &lrd,
topic_name, exp_remote_topic_fail, false, exp_local_topic_fail, exp_rd_fail);
if (!exp_local_topic_fail && !exp_remote_topic_fail && !exp_rd_fail)
sync_reader_to_writers (g_participant[0], lrd, exp_rd_wr_sync_fail ? 0 : 1);
}
access_control_fini (2);
}
#define na false
CU_TheoryDataPoints(ddssec_access_control, join_access_control) = {
CU_DataPoints(const char *,
/* */"no join access control",
/* | */"join access control pp1, valid",
/* | | */"join access control pp1 and pp2, valid",
/* | | | */"join access control pp1, invalid",
/* | | | | */"join access control pp1 and pp2, invalid"),
CU_DataPoints(bool, false, true, true, true, true), /* join access control pp 1 enabled */
CU_DataPoints(bool, false, false, true, false, true), /* join access control pp 2 enabled */
CU_DataPoints(bool, false, false, false, true, true), /* permissions pp 1 invalid */
CU_DataPoints(bool, false, false, false, false, true), /* permissions pp 2 invalid */
CU_DataPoints(bool, false, false, false, true, true), /* expect pp 1 create failure */
CU_DataPoints(bool, false, false, false, false, true), /* expect pp 2 create failure */
CU_DataPoints(bool, false, false, false, na, na), /* expect handshake failure */
};
#undef na
CU_Theory(
(const char * test_descr, bool join_ac_pp1, bool join_ac_pp2, bool perm_inv_pp1, bool perm_inv_pp2, bool exp_pp1_fail, bool exp_pp2_fail, bool exp_hs_fail),
ddssec_access_control, join_access_control, .timeout=30)
{
print_test_msg ("running test join_access_control: %s\n", test_descr);
char topic_name[100];
create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name));
/* create ca and id1/id2 certs that will not expire during this test */
char *ca, *id1, *id2, *id1_subj, *id2_subj;
ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600);
id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj);
id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj);
/* localtime will be converted to gmtime in get_permissions_grant */
dds_time_t now = dds_time ();
char * perm_topic = get_permissions_topic (topic_name);
char * grants[] = {
get_permissions_grant ("id1", id1_subj, perm_inv_pp1 ? "99" : NULL, now, now + DDS_SECS(3600), perm_topic, perm_topic, NULL),
get_permissions_grant ("id2", id2_subj, perm_inv_pp2 ? "99" : NULL, now, now + DDS_SECS(3600), perm_topic, perm_topic, NULL) };
char * perm_config = get_permissions_config (grants, 2, true);
struct kvp governance_vars_pp1[] = { { "ENABLE_JOIN_AC", join_ac_pp1 ? "true" : "false", 1 }, { NULL, NULL, 0 } };
struct kvp governance_vars_pp2[] = { { "ENABLE_JOIN_AC", join_ac_pp2 ? "true" : "false", 1 }, { NULL, NULL, 0 } };
char * gov_config_pp1 = get_governance_config (governance_vars_pp1, true);
char * gov_config_pp2 = get_governance_config (governance_vars_pp2, true);
const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem");
access_control_init (
2,
(const char *[]) { id1, id2 },
(const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY },
(const char *[]) { ca, ca },
(bool []) { exp_pp1_fail, exp_pp2_fail }, NULL, NULL,
(bool []) { true, true }, (const char *[]) { gov_config_pp1, gov_config_pp2 },
(bool []) { true, true }, (const char *[]) { perm_config, perm_config },
(bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca });
if (!exp_pp1_fail && !exp_pp2_fail)
validate_handshake (DDS_DOMAINID, exp_hs_fail, NULL, NULL, NULL);
access_control_fini (2);
ddsrt_free (gov_config_pp1);
ddsrt_free (gov_config_pp2);
ddsrt_free (perm_topic);
ddsrt_free (grants[0]);
ddsrt_free (grants[1]);
ddsrt_free (perm_config);
ddsrt_free (ca);
ddsrt_free (id1_subj);
ddsrt_free (id2_subj);
ddsrt_free (id1);
ddsrt_free (id2);
}

View file

@ -309,8 +309,8 @@ CU_Theory(
dds_time_t now = dds_time ();
char * grants[] = {
get_permissions_grant ("id1", id1_subj, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL),
get_permissions_grant ("id2", id2_subj, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL) };
get_permissions_grant ("id1", id1_subj, NULL, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL),
get_permissions_grant ("id2", id2_subj, NULL, now - DDS_SECS(D(1)), now + DDS_SECS(D(1)), NULL, NULL, NULL) };
char * perm_config = get_permissions_config (grants, 2, true);
authentication_init (id1, ID1K, ca, id2, ID1K, ca, NULL, perm_config, id1_local_fail, id2_local_fail);
validate_handshake (DDS_DOMAINID1, id1_local_fail, NULL, NULL, NULL);
@ -318,6 +318,7 @@ CU_Theory(
if (write_read_dur > 0)
{
rd_wr_init (g_participant1, &g_pub, &g_pub_tp, &g_wr, g_participant2, &g_sub, &g_sub_tp, &g_rd, topic_name);
sync_writer_to_readers(g_participant1, g_wr, 1);
write_read_for (g_wr, g_participant2, g_rd, DDS_MSECS (write_read_dur), false, exp_read_fail);
}
authentication_fini (!id1_local_fail, !id2_local_fail);

View file

@ -20,18 +20,49 @@
#include "dds/security/core/dds_security_utils.h"
#include "access_control_wrapper.h"
int init_access_control(const char *argument, void **context, struct ddsi_domaingv *gv);
int finalize_access_control(void *context);
enum ac_plugin_mode {
PLUGIN_MODE_ALL_OK,
PLUGIN_MODE_WRAPPED,
PLUGIN_MODE_NOT_ALLOWED,
PLUGIN_MODE_MISSING_FUNC
};
enum ac_plugin_not_allowed {
NOT_ALLOWED_ID_LOCAL_PP,
NOT_ALLOWED_ID_LOCAL_TOPIC,
NOT_ALLOWED_ID_LOCAL_PUB,
NOT_ALLOWED_ID_LOCAL_SUB,
NOT_ALLOWED_ID_REMOTE_PERM,
NOT_ALLOWED_ID_REMOTE_PP,
NOT_ALLOWED_ID_REMOTE_TOPIC,
NOT_ALLOWED_ID_REMOTE_WRITER,
NOT_ALLOWED_ID_REMOTE_READER,
NOT_ALLOWED_ID_REMOTE_READER_RELAY_ONLY
};
#define NOT_ALLOWED_LOCAL_PP (1u << NOT_ALLOWED_ID_LOCAL_PP)
#define NOT_ALLOWED_LOCAL_TOPIC (1u << NOT_ALLOWED_ID_LOCAL_TOPIC)
#define NOT_ALLOWED_LOCAL_PUB (1u << NOT_ALLOWED_ID_LOCAL_PUB)
#define NOT_ALLOWED_LOCAL_SUB (1u << NOT_ALLOWED_ID_LOCAL_SUB)
#define NOT_ALLOWED_REMOTE_PERM (1u << NOT_ALLOWED_ID_REMOTE_PERM)
#define NOT_ALLOWED_REMOTE_PP (1u << NOT_ALLOWED_ID_REMOTE_PP)
#define NOT_ALLOWED_REMOTE_TOPIC (1u << NOT_ALLOWED_ID_REMOTE_TOPIC)
#define NOT_ALLOWED_REMOTE_WRITER (1u << NOT_ALLOWED_ID_REMOTE_WRITER)
#define NOT_ALLOWED_REMOTE_READER (1u << NOT_ALLOWED_ID_REMOTE_READER)
#define NOT_ALLOWED_REMOTE_READER_RELAY_ONLY (1u << NOT_ALLOWED_ID_REMOTE_READER_RELAY_ONLY)
/**
* Implementation structure for storing encapsulated members of the instance
* while giving only the interface definition to user
*/
struct dds_security_access_control_impl {
dds_security_access_control base;
dds_security_access_control *instance;
enum ac_plugin_mode mode;
uint32_t not_allowed_mask;
};
static DDS_Security_PermissionsHandle validate_local_permissions(
@ -42,15 +73,17 @@ static DDS_Security_PermissionsHandle validate_local_permissions(
const DDS_Security_Qos *participant_qos,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(auth_plugin);
DDSRT_UNUSED_ARG(auth_plugin);
DDSRT_UNUSED_ARG(identity);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(participant_qos);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->validate_local_permissions(impl->instance, auth_plugin, identity, domain_id, participant_qos, ex);
default:
return 1;
}
}
static DDS_Security_PermissionsHandle validate_remote_permissions(
dds_security_access_control *instance,
@ -61,31 +94,54 @@ static DDS_Security_PermissionsHandle validate_remote_permissions(
const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(auth_plugin);
DDSRT_UNUSED_ARG(local_identity_handle);
DDSRT_UNUSED_ARG(remote_identity_handle);
DDSRT_UNUSED_ARG(remote_permissions_token);
DDSRT_UNUSED_ARG(remote_credential_token);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_PERM)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: validate_remote_permissions");
return 0;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->validate_remote_permissions(impl->instance, auth_plugin, local_identity_handle, remote_identity_handle,
remote_permissions_token, remote_credential_token, ex);
static DDS_Security_boolean check_create_participant( dds_security_access_control *instance,
default:
return 0;
}
}
static DDS_Security_boolean check_create_participant(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const DDS_Security_Qos *participant_qos,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(participant_qos);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_PP)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_create_participant");
return false;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_create_participant(impl->instance, permissions_handle, domain_id, participant_qos, ex);
default:
return true;
}
}
static DDS_Security_boolean check_create_datawriter( dds_security_access_control *instance,
static DDS_Security_boolean check_create_datawriter(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const char *topic_name,
@ -94,18 +150,30 @@ static DDS_Security_boolean check_create_datawriter( dds_security_access_control
const DDS_Security_DataTags *data_tag,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(topic_name);
DDSRT_UNUSED_ARG(writer_qos);
DDSRT_UNUSED_ARG(partition);
DDSRT_UNUSED_ARG(data_tag);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_PUB)
{
if (topic_name && strncmp (topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_create_datawriter");
return false;
}
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_create_datawriter(impl->instance, permissions_handle, domain_id, topic_name, writer_qos, partition, data_tag, ex);
default:
return true;
}
}
static DDS_Security_boolean check_create_datareader( dds_security_access_control *instance,
static DDS_Security_boolean check_create_datareader(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const char *topic_name,
@ -114,32 +182,51 @@ static DDS_Security_boolean check_create_datareader( dds_security_access_control
const DDS_Security_DataTags *data_tag,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(topic_name);
DDSRT_UNUSED_ARG(reader_qos);
DDSRT_UNUSED_ARG(partition);
DDSRT_UNUSED_ARG(data_tag);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_SUB)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_create_datareader");
return false;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_create_datareader(impl->instance, permissions_handle, domain_id, topic_name, reader_qos, partition, data_tag, ex);
default:
return true;
}
}
static DDS_Security_boolean check_create_topic( dds_security_access_control *instance,
static DDS_Security_boolean check_create_topic(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const char *topic_name,
const DDS_Security_Qos *qos,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(topic_name);
DDSRT_UNUSED_ARG(qos);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_TOPIC)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_create_topic");
return false;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_create_topic(impl->instance, permissions_handle, domain_id, topic_name, qos, ex);
default:
return true;
}
}
static DDS_Security_boolean check_local_datawriter_register_instance(
dds_security_access_control *instance,
@ -148,13 +235,17 @@ static DDS_Security_boolean check_local_datawriter_register_instance(
const DDS_Security_DynamicData *key,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(writer);
DDSRT_UNUSED_ARG(key);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->check_local_datawriter_register_instance(impl->instance, permissions_handle, writer, key, ex);
default:
return true;
}
}
static DDS_Security_boolean check_local_datawriter_dispose_instance(
dds_security_access_control *instance,
@ -163,70 +254,138 @@ static DDS_Security_boolean check_local_datawriter_dispose_instance(
const DDS_Security_DynamicData key,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(writer);
DDSRT_UNUSED_ARG(key);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->check_local_datawriter_dispose_instance(impl->instance, permissions_handle, writer, key, ex);
default:
return true;
}
}
static DDS_Security_boolean check_remote_participant( dds_security_access_control *instance,
static DDS_Security_boolean check_remote_participant(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const DDS_Security_ParticipantBuiltinTopicDataSecure *participant_data,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(participant_data);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_PP)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_remote_participant");
return false;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_remote_participant(impl->instance, permissions_handle, domain_id, participant_data, ex);
default:
return true;
}
}
static DDS_Security_boolean check_remote_datawriter( dds_security_access_control *instance,
static DDS_Security_boolean check_remote_datawriter(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(publication_data);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_WRITER)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_remote_datawriter");
return false;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_remote_datawriter(impl->instance, permissions_handle, domain_id, publication_data, ex);
default:
return true;
}
}
static DDS_Security_boolean check_remote_datareader( dds_security_access_control *instance,
static DDS_Security_boolean check_remote_datareader(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data,
DDS_Security_boolean *relay_only, DDS_Security_SecurityException *ex)
DDS_Security_boolean *relay_only,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(subscription_data);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_READER)
{
if (subscription_data->topic_name && strncmp (subscription_data->topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_remote_datareader");
return false;
}
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
{
bool ret;
if ((ret = impl->instance->check_remote_datareader(impl->instance, permissions_handle, domain_id, subscription_data, relay_only, ex)))
{
/* Only relay_only for the user reader, not the builtin ones. */
if (impl->mode == PLUGIN_MODE_NOT_ALLOWED && impl->not_allowed_mask & NOT_ALLOWED_REMOTE_READER_RELAY_ONLY)
{
if (subscription_data->topic_name && strncmp (subscription_data->topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0)
*relay_only = true;
}
}
return ret;
}
default:
*relay_only = false;
return true;
}
}
static DDS_Security_boolean check_remote_topic( dds_security_access_control *instance,
static DDS_Security_boolean check_remote_topic(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const DDS_Security_DomainId domain_id,
const DDS_Security_TopicBuiltinTopicData *topic_data,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(domain_id);
DDSRT_UNUSED_ARG(topic_data);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_NOT_ALLOWED:
if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_TOPIC)
{
ex->code = 1;
ex->message = ddsrt_strdup ("not_allowed: check_remote_topic");
return false;
}
/* fall through */
case PLUGIN_MODE_WRAPPED:
return impl->instance->check_remote_topic(impl->instance, permissions_handle, domain_id, topic_data, ex);
default:
return true;
}
}
static DDS_Security_boolean check_local_datawriter_match(
dds_security_access_control *instance,
@ -236,14 +395,17 @@ static DDS_Security_boolean check_local_datawriter_match(
const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(writer_permissions_handle);
DDSRT_UNUSED_ARG(reader_permissions_handle);
DDSRT_UNUSED_ARG(publication_data);
DDSRT_UNUSED_ARG(subscription_data);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->check_local_datawriter_match(impl->instance, writer_permissions_handle, reader_permissions_handle, publication_data, subscription_data, ex);
default:
return true;
}
}
static DDS_Security_boolean check_local_datareader_match(
dds_security_access_control *instance,
@ -253,14 +415,17 @@ static DDS_Security_boolean check_local_datareader_match(
const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(reader_permissions_handle);
DDSRT_UNUSED_ARG(writer_permissions_handle);
DDSRT_UNUSED_ARG(subscription_data);
DDSRT_UNUSED_ARG(publication_data);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->check_local_datareader_match(impl->instance, reader_permissions_handle, writer_permissions_handle, subscription_data, publication_data, ex);
default:
return true;
}
}
static DDS_Security_boolean check_remote_datawriter_register_instance(
dds_security_access_control *instance,
@ -271,15 +436,17 @@ static DDS_Security_boolean check_remote_datawriter_register_instance(
const DDS_Security_InstanceHandle instance_handle,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(reader);
DDSRT_UNUSED_ARG(publication_handle);
DDSRT_UNUSED_ARG(key);
DDSRT_UNUSED_ARG(instance_handle);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->check_remote_datawriter_register_instance(impl->instance, permissions_handle, reader, publication_handle, key, instance_handle, ex);
default:
return true;
}
}
static DDS_Security_boolean check_remote_datawriter_dispose_instance(
dds_security_access_control *instance,
@ -289,14 +456,17 @@ static DDS_Security_boolean check_remote_datawriter_dispose_instance(
const DDS_Security_DynamicData key,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(reader);
DDSRT_UNUSED_ARG(publication_handle);
DDSRT_UNUSED_ARG(key);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->check_remote_datawriter_dispose_instance(impl->instance, permissions_handle, reader, publication_handle, key, ex);
default:
return true;
}
}
static DDS_Security_boolean get_permissions_token(
dds_security_access_control *instance,
@ -304,13 +474,19 @@ static DDS_Security_boolean get_permissions_token(
const DDS_Security_PermissionsHandle handle,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(handle);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->get_permissions_token(impl->instance, permissions_token, handle, ex);
default:
memset(permissions_token, 0, sizeof(*permissions_token));
permissions_token->class_id = ddsrt_strdup ("");
return true;
}
}
static DDS_Security_boolean get_permissions_credential_token(
dds_security_access_control *instance,
@ -318,43 +494,69 @@ static DDS_Security_boolean get_permissions_credential_token(
const DDS_Security_PermissionsHandle handle,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_credential_token);
DDSRT_UNUSED_ARG(handle);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->get_permissions_credential_token(impl->instance, permissions_credential_token, handle, ex);
default:
return true;
}
}
static DDS_Security_boolean set_listener( dds_security_access_control *instance,
static DDS_Security_boolean set_listener(
dds_security_access_control *instance,
const dds_security_access_control_listener *listener,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(listener);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->set_listener (impl->instance, listener, ex);
default:
return true;
}
}
static DDS_Security_boolean return_permissions_token( dds_security_access_control *instance,
static DDS_Security_boolean return_permissions_token(
dds_security_access_control *instance,
const DDS_Security_PermissionsToken *token,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_permissions_token (impl->instance, token, ex);
default:
ddsrt_free (token->class_id);
return true;
}
}
static DDS_Security_boolean return_permissions_credential_token(
dds_security_access_control *instance,
const DDS_Security_PermissionsCredentialToken *permissions_credential_token,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_credential_token);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_permissions_credential_token(impl->instance, permissions_credential_token, ex);
default:
return true;
}
}
static DDS_Security_boolean get_participant_sec_attributes(
dds_security_access_control *instance,
@ -362,26 +564,36 @@ static DDS_Security_boolean get_participant_sec_attributes(
DDS_Security_ParticipantSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->get_participant_sec_attributes(impl->instance, permissions_handle, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean get_topic_sec_attributes( dds_security_access_control *instance,
static DDS_Security_boolean get_topic_sec_attributes(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
const char *topic_name,
DDS_Security_TopicSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(topic_name);
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->get_topic_sec_attributes(impl->instance, permissions_handle, topic_name, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean get_datawriter_sec_attributes(
dds_security_access_control *instance,
@ -392,15 +604,17 @@ static DDS_Security_boolean get_datawriter_sec_attributes(
DDS_Security_EndpointSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(topic_name);
DDSRT_UNUSED_ARG(partition);
DDSRT_UNUSED_ARG(data_tag);
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->get_datawriter_sec_attributes(impl->instance, permissions_handle, topic_name, partition, data_tag, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean get_datareader_sec_attributes(
dds_security_access_control *instance,
@ -411,76 +625,114 @@ static DDS_Security_boolean get_datareader_sec_attributes(
DDS_Security_EndpointSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(topic_name);
DDSRT_UNUSED_ARG(partition);
DDSRT_UNUSED_ARG(data_tag);
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->get_datareader_sec_attributes(impl->instance, permissions_handle, topic_name, partition, data_tag, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean return_participant_sec_attributes(
dds_security_access_control *instance,
const DDS_Security_ParticipantSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_participant_sec_attributes(impl->instance, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean return_topic_sec_attributes(
dds_security_access_control *instance,
const DDS_Security_TopicSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_topic_sec_attributes(impl->instance, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean return_datawriter_sec_attributes(
dds_security_access_control *instance,
const DDS_Security_EndpointSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_datawriter_sec_attributes(impl->instance, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean return_datareader_sec_attributes(
dds_security_access_control *instance,
const DDS_Security_EndpointSecurityAttributes *attributes,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(attributes);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_datareader_sec_attributes(impl->instance, attributes, ex);
default:
return true;
}
}
static DDS_Security_boolean return_permissions_handle(
dds_security_access_control *instance,
const DDS_Security_PermissionsHandle permissions_handle,
DDS_Security_SecurityException *ex)
{
DDSRT_UNUSED_ARG(permissions_handle);
DDSRT_UNUSED_ARG(ex);
DDSRT_UNUSED_ARG(instance);
struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance;
switch (impl->mode)
{
case PLUGIN_MODE_WRAPPED:
case PLUGIN_MODE_NOT_ALLOWED:
return impl->instance->return_permissions_handle(impl->instance, permissions_handle, ex);
default:
return true;
}
}
static struct dds_security_access_control_impl * init_test_access_control_common()
static struct dds_security_access_control_impl * init_test_access_control_common(const char *argument, bool wrapped, struct ddsi_domaingv *gv)
{
struct dds_security_access_control_impl *impl = ddsrt_malloc(sizeof(*impl));
memset(impl, 0, sizeof(*impl));
if (wrapped)
{
if (init_access_control(argument, (void **)&impl->instance, gv) != DDS_SECURITY_SUCCESS)
return NULL;
}
impl->base.validate_local_permissions = &validate_local_permissions;
impl->base.validate_remote_permissions = &validate_remote_permissions;
impl->base.check_create_participant = &check_create_participant;
@ -514,40 +766,90 @@ static struct dds_security_access_control_impl * init_test_access_control_common
return impl;
}
int32_t init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv)
static int finalize_test_access_control_common(struct dds_security_access_control_impl * impl, bool wrapped)
{
int32_t ret;
if (wrapped && (ret = finalize_access_control(impl->instance)) != DDS_SECURITY_SUCCESS)
return ret;
ddsrt_free(impl);
return DDS_SECURITY_SUCCESS;
}
int init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv)
{
DDSRT_UNUSED_ARG(argument);
DDSRT_UNUSED_ARG(context);
DDSRT_UNUSED_ARG(gv);
struct dds_security_access_control_impl *impl = init_test_access_control_common();
struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, false, gv);
impl->mode = PLUGIN_MODE_ALL_OK;
*context = impl;
return 0;
}
int32_t finalize_test_access_control_all_ok(void *context)
int finalize_test_access_control_all_ok(void *context)
{
assert(((struct dds_security_access_control_impl *)context)->mode == PLUGIN_MODE_ALL_OK);
ddsrt_free(context);
return 0;
struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context;
assert(impl->mode == PLUGIN_MODE_ALL_OK);
return finalize_test_access_control_common(impl, false);
}
int32_t init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_access_control_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv)
{
struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, true, gv);
if (!impl)
return DDS_SECURITY_FAILED;
impl->mode = PLUGIN_MODE_WRAPPED;
*context = impl;
return DDS_SECURITY_SUCCESS;
}
int finalize_test_access_control_wrapped(void *context)
{
struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context;
assert(impl->mode == PLUGIN_MODE_WRAPPED);
return finalize_test_access_control_common(impl, true);
}
int init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv)
{
DDSRT_UNUSED_ARG(argument);
DDSRT_UNUSED_ARG(context);
DDSRT_UNUSED_ARG(gv);
struct dds_security_access_control_impl *impl = init_test_access_control_common();
struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, false, gv);
impl->base.check_create_datareader = NULL;
impl->mode = PLUGIN_MODE_MISSING_FUNC;
*context = impl;
return 0;
}
int32_t finalize_test_access_control_missing_func(void *context)
int finalize_test_access_control_missing_func(void *context)
{
assert(((struct dds_security_access_control_impl *)context)->mode == PLUGIN_MODE_MISSING_FUNC);
ddsrt_free(context);
return 0;
struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context;
assert(impl->mode == PLUGIN_MODE_MISSING_FUNC);
return finalize_test_access_control_common(impl, false);
}
#define INIT_NOT_ALLOWED(name_, mask_) \
int init_test_access_control_##name_ (const char *argument, void **context, struct ddsi_domaingv *gv) \
{ \
DDSRT_UNUSED_ARG(context); \
struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, true, gv); \
impl->mode = PLUGIN_MODE_NOT_ALLOWED; \
impl->not_allowed_mask = mask_; \
*context = impl; \
return 0; \
}
INIT_NOT_ALLOWED(local_participant_not_allowed, NOT_ALLOWED_LOCAL_PP)
INIT_NOT_ALLOWED(local_topic_not_allowed, NOT_ALLOWED_LOCAL_TOPIC)
INIT_NOT_ALLOWED(local_publishing_not_allowed, NOT_ALLOWED_LOCAL_PUB)
INIT_NOT_ALLOWED(local_subscribing_not_allowed, NOT_ALLOWED_LOCAL_SUB)
INIT_NOT_ALLOWED(remote_permissions_invalidate, NOT_ALLOWED_REMOTE_PERM)
INIT_NOT_ALLOWED(remote_participant_not_allowed, NOT_ALLOWED_REMOTE_PP)
INIT_NOT_ALLOWED(remote_topic_not_allowed, NOT_ALLOWED_REMOTE_TOPIC)
INIT_NOT_ALLOWED(remote_writer_not_allowed, NOT_ALLOWED_REMOTE_WRITER)
INIT_NOT_ALLOWED(remote_reader_not_allowed, NOT_ALLOWED_REMOTE_READER)
INIT_NOT_ALLOWED(remote_reader_relay_only, NOT_ALLOWED_REMOTE_READER_RELAY_ONLY)
int finalize_test_access_control_not_allowed(void *context)
{
struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context;
assert(impl->mode == PLUGIN_MODE_NOT_ALLOWED);
return finalize_test_access_control_common(impl, true);
}

View file

@ -16,12 +16,36 @@
#include "dds/security/dds_security_api.h"
#include "dds/security/access_control_wrapper_export.h"
/* Topic name prefix expected by this wrapper when running in not-allowed
mode. This prefix is used to exclude built-in topics from being disallowed. */
#define AC_WRAPPER_TOPIC_PREFIX "ddssec_access_control_"
/* Init in all-ok mode: all functions return success without calling the actual plugin */
SECURITY_EXPORT int32_t init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_access_control_all_ok(void *context);
SECURITY_EXPORT int init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_access_control_all_ok(void *context);
/* Init in missing function mode: one of the function pointers is null */
SECURITY_EXPORT int32_t init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_access_control_missing_func(void *context);
SECURITY_EXPORT int init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_access_control_missing_func(void *context);
SECURITY_EXPORT int init_test_access_control_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_access_control_wrapped(void *context);
/* Init functions for not-allowed modes */
#define INIT_NOT_ALLOWED_DECL(name_) \
SECURITY_EXPORT int init_test_access_control_##name_ (const char *argument, void **context, struct ddsi_domaingv *gv);
INIT_NOT_ALLOWED_DECL(local_participant_not_allowed)
INIT_NOT_ALLOWED_DECL(local_topic_not_allowed)
INIT_NOT_ALLOWED_DECL(local_publishing_not_allowed)
INIT_NOT_ALLOWED_DECL(local_subscribing_not_allowed)
INIT_NOT_ALLOWED_DECL(remote_permissions_invalidate)
INIT_NOT_ALLOWED_DECL(remote_participant_not_allowed)
INIT_NOT_ALLOWED_DECL(remote_topic_not_allowed)
INIT_NOT_ALLOWED_DECL(remote_writer_not_allowed)
INIT_NOT_ALLOWED_DECL(remote_reader_not_allowed)
INIT_NOT_ALLOWED_DECL(remote_reader_relay_only)
SECURITY_EXPORT int finalize_test_access_control_not_allowed(void *context);
#endif /* SECURITY_CORE_TEST_ACCESS_CONTROL_WRAPPER_H_ */

View file

@ -22,8 +22,8 @@
#include "test_identity.h"
#include "plugin_wrapper_msg_q.h"
int32_t init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv);
int32_t finalize_authentication(void *context);
int init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv);
int finalize_authentication(void *context);
enum auth_plugin_mode {
PLUGIN_MODE_ALL_OK,
@ -482,7 +482,7 @@ static struct dds_security_authentication_impl * init_test_authentication_common
return impl;
}
int32_t init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv)
{
DDSRT_UNUSED_ARG(argument);
DDSRT_UNUSED_ARG(context);
@ -493,14 +493,14 @@ int32_t init_test_authentication_all_ok(const char *argument, void **context, st
return 0;
}
int32_t finalize_test_authentication_all_ok(void *context)
int finalize_test_authentication_all_ok(void *context)
{
assert(((struct dds_security_authentication_impl *)context)->mode == PLUGIN_MODE_ALL_OK);
ddsrt_free(context);
return 0;
}
int32_t init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv)
{
DDSRT_UNUSED_ARG(argument);
DDSRT_UNUSED_ARG(context);
@ -512,14 +512,14 @@ int32_t init_test_authentication_missing_func(const char *argument, void **conte
return 0;
}
int32_t finalize_test_authentication_missing_func(void *context)
int finalize_test_authentication_missing_func(void *context)
{
assert(((struct dds_security_authentication_impl *)context)->mode == PLUGIN_MODE_MISSING_FUNC);
ddsrt_free(context);
return 0;
}
int32_t init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv)
{
DDSRT_UNUSED_ARG(argument);
DDSRT_UNUSED_ARG(context);
@ -527,7 +527,7 @@ int32_t init_test_authentication_init_error(const char *argument, void **context
return 1;
}
int32_t finalize_test_authentication_init_error(void *context)
int finalize_test_authentication_init_error(void *context)
{
DDSRT_UNUSED_ARG(context);
return 0;
@ -537,9 +537,9 @@ int32_t finalize_test_authentication_init_error(void *context)
* Init and fini functions for using wrapped mode for the authentication plugin.
* These functions assumes that there are no concurrent calls, as the static
* variables used here are not protected by a lock. */
int32_t init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv)
{
int32_t ret;
int ret;
struct dds_security_authentication_impl *impl = init_test_authentication_common();
impl->mode = PLUGIN_MODE_WRAPPED;
@ -553,9 +553,9 @@ int32_t init_test_authentication_wrapped(const char *argument, void **context, s
return ret;
}
int32_t finalize_test_authentication_wrapped(void *context)
int finalize_test_authentication_wrapped(void *context)
{
int32_t ret;
int ret;
struct dds_security_authentication_impl *impl = context;
assert(impl->mode == PLUGIN_MODE_WRAPPED);
deinit_message_queue(&impl->msg_queue);

View file

@ -18,20 +18,20 @@
#include "plugin_wrapper_msg_q.h"
/* Init in wrapper mode */
SECURITY_EXPORT int32_t init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_authentication_wrapped(void *context);
SECURITY_EXPORT int init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_authentication_wrapped(void *context);
/* Init in all-ok mode: all functions return success without calling the actual plugin */
SECURITY_EXPORT int32_t init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_authentication_all_ok(void *context);
SECURITY_EXPORT int init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_authentication_all_ok(void *context);
/* Init in missing function mode: one of the function pointers is null */
SECURITY_EXPORT int32_t init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_authentication_missing_func(void *context);
SECURITY_EXPORT int init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_authentication_missing_func(void *context);
/* Init function fails */
SECURITY_EXPORT int32_t init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_authentication_init_error(void *context);
SECURITY_EXPORT int init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_authentication_init_error(void *context);
SECURITY_EXPORT struct message * test_authentication_plugin_take_msg(dds_domainid_t domain_id, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, dds_duration_t timeout);
SECURITY_EXPORT void test_authentication_plugin_release_msg(struct message *msg);

View file

@ -22,8 +22,8 @@
#include "dds/security/core/dds_security_utils.h"
#include "cryptography_wrapper.h"
int32_t init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv);
int32_t finalize_crypto(void *context);
int init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv);
int finalize_crypto(void *context);
enum crypto_plugin_mode {
PLUGIN_MODE_ALL_OK,
@ -754,16 +754,16 @@ static struct dds_security_cryptography_impl * init_test_cryptography_common(con
return impl;
}
static int32_t finalize_test_cryptography_common(struct dds_security_cryptography_impl * impl, bool wrapped)
static int finalize_test_cryptography_common(struct dds_security_cryptography_impl * impl, bool wrapped)
{
int32_t ret;
int ret;
if (wrapped && (ret = finalize_crypto(impl->instance)) != DDS_SECURITY_SUCCESS)
return ret;
ddsrt_free(impl);
return DDS_SECURITY_SUCCESS;
}
int32_t init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv)
{
struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, false, gv);
if (!impl)
@ -773,14 +773,14 @@ int32_t init_test_cryptography_all_ok(const char *argument, void **context, stru
return DDS_SECURITY_SUCCESS;
}
int32_t finalize_test_cryptography_all_ok(void *context)
int finalize_test_cryptography_all_ok(void *context)
{
struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context;
assert(impl->mode == PLUGIN_MODE_ALL_OK);
return finalize_test_cryptography_common(impl, false);
}
int32_t init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv)
{
struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, false, gv);
if (!impl)
@ -791,14 +791,14 @@ int32_t init_test_cryptography_missing_func(const char *argument, void **context
return DDS_SECURITY_SUCCESS;
}
int32_t finalize_test_cryptography_missing_func(void *context)
int finalize_test_cryptography_missing_func(void *context)
{
struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context;
assert(impl->mode == PLUGIN_MODE_MISSING_FUNC);
return finalize_test_cryptography_common(impl, false);
}
int32_t init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv)
int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv)
{
struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, true, gv);
if (!impl)
@ -808,7 +808,7 @@ int32_t init_test_cryptography_wrapped(const char *argument, void **context, str
return DDS_SECURITY_SUCCESS;
}
int32_t finalize_test_cryptography_wrapped(void *context)
int finalize_test_cryptography_wrapped(void *context)
{
struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context;
assert(impl->mode == PLUGIN_MODE_WRAPPED);

View file

@ -35,15 +35,15 @@ SECURITY_EXPORT void set_disc_protection_kinds(
SECURITY_EXPORT void set_entity_data_secret(struct dds_security_cryptography_impl * impl, const char * pp_secret, const char * groupdata_secret, const char * ep_secret);
/* Init in all-ok mode: all functions return success without calling the actual plugin */
SECURITY_EXPORT int32_t init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_cryptography_all_ok(void *context);
SECURITY_EXPORT int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_cryptography_all_ok(void *context);
/* Init in missing function mode: one of the function pointers is null */
SECURITY_EXPORT int32_t init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_cryptography_missing_func(void *context);
SECURITY_EXPORT int init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_cryptography_missing_func(void *context);
/* Init in wrapper mode */
SECURITY_EXPORT int32_t init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int32_t finalize_test_cryptography_wrapped(void *context);
SECURITY_EXPORT int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv);
SECURITY_EXPORT int finalize_test_cryptography_wrapped(void *context);
#endif /* SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ */

View file

@ -50,8 +50,8 @@ static const char *governance_xml =
" <topic_expression>*</topic_expression>"
" <enable_discovery_protection>${ENABLE_DISC_PROTECTION:-false}</enable_discovery_protection>"
" <enable_liveliness_protection>${ENABLE_LIVELINESS_PROTECTION:-false}</enable_liveliness_protection>"
" <enable_read_access_control>${ENABLE_READ_AC:-false}</enable_read_access_control>"
" <enable_write_access_control>${ENABLE_WRITE_AC:-false}</enable_write_access_control>"
" <enable_read_access_control>${ENABLE_READ_AC:-true}</enable_read_access_control>"
" <enable_write_access_control>${ENABLE_WRITE_AC:-true}</enable_write_access_control>"
" <metadata_protection_kind>${METADATA_PROTECTION_KIND:-NONE}</metadata_protection_kind>"
" <data_protection_kind>${DATA_PROTECTION_KIND:-NONE}</data_protection_kind>"
" </topic_rule>"
@ -68,7 +68,7 @@ static const char *permissions_xml_grant =
" <subject_name>${SUBJECT_NAME}</subject_name>"
" <validity><not_before>${NOT_BEFORE:-2015-09-15T01:00:00}</not_before><not_after>${NOT_AFTER:-2115-09-15T01:00:00}</not_after></validity>"
" <allow_rule>"
" <domains><id_range><min>0</min><max>230</max></id_range></domains>"
" <domains>${DOMAIN_ID:+<id>}${DOMAIN_ID:-<id_range><min>0</min><max>230</max></id_range>}${DOMAIN_ID:+</id>}</domains>"
" <publish>"
" <topics>${PUB_TOPICS:-<topic>*</topic>}</topics>"
" <partitions><partition>*</partition></partitions>"
@ -239,7 +239,7 @@ static char * get_xml_datetime(dds_time_t t, char * buf, size_t len)
return buf;
}
char * get_permissions_grant(const char * name, const char * subject,
char * get_permissions_grant(const char * name, const char * subject, const char * domain_id,
dds_time_t not_before, dds_time_t not_after, const char * pub_topics, const char * sub_topics, const char * default_policy)
{
char not_before_str[] = "0000-00-00T00:00:00Z";
@ -252,6 +252,7 @@ char * get_permissions_grant(const char * name, const char * subject,
{ "SUBJECT_NAME", subject, 1 },
{ "NOT_BEFORE", not_before_str, 1 },
{ "NOT_AFTER", not_after_str, 1 },
{ "DOMAIN_ID", domain_id, 3 },
{ "PUB_TOPICS", pub_topics, 1 },
{ "SUB_TOPICS", sub_topics, 1 },
{ "DEFAULT_POLICY", default_policy, 1 },

View file

@ -27,7 +27,7 @@ int32_t expand_lookup_unmatched (const struct kvp * lookup_table);
char * get_governance_config (struct kvp *config_vars, bool add_prefix);
char * get_permissions_topic(const char * name);
char * get_permissions_grant(const char * name, const char * subject,
char * get_permissions_grant(const char * name, const char * subject, const char * domain_id,
dds_time_t not_before, dds_time_t not_after, const char * pub_topics, const char * sub_topics, const char * default_policy);
char * get_permissions_config(char * grants[], size_t ngrants, bool add_prefix);

View file

@ -294,8 +294,9 @@ void sync_writer_to_readers (dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_c
CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
while (true)
{
ret = dds_waitset_wait (ws, &triggered, 1, DDS_SECS(5));
CU_ASSERT_FATAL (ret >= 1);
ret = dds_waitset_wait (ws, &triggered, 1, DDS_SECS(2));
CU_ASSERT_EQUAL_FATAL (exp_count > 0, ret >= 1);
if (exp_count > 0)
CU_ASSERT_EQUAL_FATAL (wr, (dds_entity_t)(intptr_t) triggered);
ret = dds_get_publication_matched_status (wr, &pub_matched);
CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
@ -306,6 +307,30 @@ void sync_writer_to_readers (dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_c
CU_ASSERT_EQUAL_FATAL (pub_matched.total_count, exp_count);
}
void sync_reader_to_writers (dds_entity_t pp_rd, dds_entity_t rd, uint32_t exp_count)
{
dds_attach_t triggered;
dds_entity_t ws = dds_create_waitset (pp_rd);
CU_ASSERT_FATAL (ws > 0);
dds_subscription_matched_status_t sub_matched;
dds_return_t ret = dds_waitset_attach (ws, rd, rd);
CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
while (true)
{
ret = dds_waitset_wait (ws, &triggered, 1, DDS_SECS(2));
CU_ASSERT_EQUAL_FATAL (exp_count > 0, ret >= 1);
if (exp_count > 0)
CU_ASSERT_EQUAL_FATAL (rd, (dds_entity_t)(intptr_t) triggered);
ret = dds_get_subscription_matched_status (rd, &sub_matched);
CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK);
if (sub_matched.total_count >= exp_count)
break;
};
dds_delete (ws);
CU_ASSERT_EQUAL_FATAL (sub_matched.total_count, exp_count);
}
char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size)
{
ddsrt_pid_t pid = ddsrt_getpid ();
@ -328,10 +353,12 @@ bool reader_wait_for_data (dds_entity_t pp, dds_entity_t rd, dds_duration_t dur)
return ret > 0;
}
void rd_wr_init(
void rd_wr_init_fail(
dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr,
dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd,
const char * topic_name)
const char * topic_name,
bool exp_pubtp_fail, bool exp_wr_fail,
bool exp_subtp_fail, bool exp_rd_fail)
{
dds_qos_t * qos = dds_create_qos ();
CU_ASSERT_FATAL (qos != NULL);
@ -344,19 +371,37 @@ void rd_wr_init(
*sub = dds_create_subscriber (pp_rd, NULL, NULL);
CU_ASSERT_FATAL (*sub > 0);
*pub_tp = dds_create_topic (pp_wr, &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL);
CU_ASSERT_FATAL (*pub_tp > 0);
CU_ASSERT_EQUAL_FATAL (exp_pubtp_fail, *pub_tp <= 0);
*sub_tp = dds_create_topic (pp_rd, &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL);
CU_ASSERT_FATAL (*sub_tp > 0);
CU_ASSERT_EQUAL_FATAL (exp_subtp_fail, *sub_tp <= 0);
if (!exp_pubtp_fail)
{
*wr = dds_create_writer (*pub, *pub_tp, qos, NULL);
CU_ASSERT_FATAL (*wr > 0);
CU_ASSERT_EQUAL_FATAL (exp_wr_fail, *wr <= 0);
if (exp_wr_fail)
goto fail;
dds_set_status_mask (*wr, DDS_PUBLICATION_MATCHED_STATUS);
}
if (!exp_subtp_fail)
{
*rd = dds_create_reader (*sub, *sub_tp, qos, NULL);
CU_ASSERT_FATAL (*rd > 0);
dds_set_status_mask (*rd, DDS_DATA_AVAILABLE_STATUS);
sync_writer_to_readers(pp_wr, *wr, 1);
CU_ASSERT_EQUAL_FATAL (exp_rd_fail, *rd <= 0);
if (exp_rd_fail)
goto fail;
dds_set_status_mask (*rd, DDS_SUBSCRIPTION_MATCHED_STATUS);
}
fail:
dds_delete_qos (qos);
}
void rd_wr_init(
dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr,
dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd,
const char * topic_name)
{
rd_wr_init_fail (pp_wr, pub, pub_tp, wr, pp_rd, sub, sub_tp, rd, topic_name, false, false, false, false);
}
void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail)
{
SecurityCoreTests_Type1 sample = { 1, 1 };
@ -367,6 +412,7 @@ void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_du
dds_time_t tend = dds_time () + dur;
bool write_fail = false, read_fail = false;
dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS);
do
{
print_test_msg ("write\n");

View file

@ -56,11 +56,18 @@ void validate_handshake_nofail (dds_domainid_t domain_id);
void handshake_list_fini(struct Handshake *hs_list, int nhs);
char *create_topic_name(const char *prefix, uint32_t nr, char *name, size_t size);
void sync_writer_to_readers(dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_count);
void sync_reader_to_writers (dds_entity_t pp_rd, dds_entity_t rd, uint32_t exp_count);
bool reader_wait_for_data(dds_entity_t pp, dds_entity_t rd, dds_duration_t dur);
void rd_wr_init(
dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr,
dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd,
const char * topic_name);
void rd_wr_init_fail(
dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr,
dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd,
const char * topic_name,
bool exp_pubtp_fail, bool exp_wr_fail,
bool exp_subtp_fail, bool exp_rd_fail);
void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail);
#endif /* SECURITY_CORE_TEST_UTILS_H_ */