You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ch...@apache.org on 2016/03/21 22:42:23 UTC

qpid-dispatch git commit: Added policy support code for link name matching.

Repository: qpid-dispatch
Updated Branches:
  refs/heads/crolke-DISPATCH-188-1 25af9cd7a -> 1aea48edc


Added policy support code for link name matching.


Project: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/commit/1aea48ed
Tree: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/tree/1aea48ed
Diff: http://git-wip-us.apache.org/repos/asf/qpid-dispatch/diff/1aea48ed

Branch: refs/heads/crolke-DISPATCH-188-1
Commit: 1aea48edcfffa35cb47c67babc294594087ace64
Parents: 25af9cd
Author: Chuck Rolke <cr...@redhat.com>
Authored: Mon Mar 21 17:33:50 2016 -0400
Committer: Chuck Rolke <cr...@redhat.com>
Committed: Mon Mar 21 17:33:50 2016 -0400

----------------------------------------------------------------------
 src/policy.c           | 142 +++++++++++++++++++++++++++++++++++---------
 src/policy_internal.h  | 100 +++++++++++++++++++++++++++++++
 tests/CMakeLists.txt   |   1 +
 tests/policy_test.c    |  89 +++++++++++++++++++++++++++
 tests/run_unit_tests.c |   2 +
 5 files changed, 306 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/1aea48ed/src/policy.c
----------------------------------------------------------------------
diff --git a/src/policy.c b/src/policy.c
index 075e89b..0cb96b3 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -20,36 +20,21 @@
 #include <Python.h>
 #include "qpid/dispatch/python_embedded.h"
 #include "policy.h"
+#include "policy_internal.h"
 #include <stdio.h>
 #include <string.h>
 #include "dispatch_private.h"
 #include "connection_manager_private.h"
 #include "qpid/dispatch/container.h"
 #include "qpid/dispatch/server.h"
-#include "qpid/dispatch/message.h"
-#include <proton/engine.h>
 #include <proton/message.h>
 #include <proton/condition.h>
 #include <proton/connection.h>
 #include <proton/transport.h>
 #include <proton/error.h>
 #include <proton/event.h>
-#include "qpid/dispatch/ctools.h"
-#include "qpid/dispatch/hash.h"
-#include "qpid/dispatch/threading.h"
-#include "qpid/dispatch/iterator.h"
-#include "qpid/dispatch/log.h"
 
 
-/**
- * Private Function Prototypes
- */
-void qd_policy_private_deny_amqp_connection(pn_connection_t *conn, const char *cond_name, const char *cond_descr);
-void qd_policy_deny_amqp_session(pn_session_t *ssn, qd_connection_t *qd_conn);
-void _qd_policy_deny_amqp_link(pn_link_t *link, qd_connection_t *qd_conn, char * s_or_r);
-void _qd_policy_deny_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_conn);
-void _qd_policy_deny_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *qd_conn);
-
 //
 // TODO: when policy dev is more complete lower the log level
 //
@@ -389,13 +374,9 @@ bool qd_policy_open_lookup_user(
     return res;
 }
 
-/** Set the error condition and close the connection.
- * Over the wire this will send an open frame followed
- * immediately by a close frame with the error condition.
- * @param[in] conn proton connection being closed
- * @param[in] cond_name condition name
- * @param[in] cond_descr condition description
- **/ 
+
+//
+//
 void qd_policy_private_deny_amqp_connection(pn_connection_t *conn, const char *cond_name, const char *cond_descr)
 {
     pn_condition_t * cond = pn_connection_condition(conn);
@@ -405,11 +386,8 @@ void qd_policy_private_deny_amqp_connection(pn_connection_t *conn, const char *c
 }
 
 
-/** Internal function to deny an amqp session
- * The session is closed with a condition and the denial is counted.
- * @param[in,out] ssn proton session
- * @param[in,out] qd_conn dispatch connection
- */
+//
+//
 void qd_policy_deny_amqp_session(pn_session_t *ssn, qd_connection_t *qd_conn)
 {
     pn_condition_t * cond = pn_session_condition(ssn);
@@ -503,6 +481,114 @@ void _qd_policy_deny_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *qd_
 
 //
 //
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+char * _qd_policy_link_user_name_subst(const char *uname, const char *proposed, char *obuf, int osize)
+{
+    if (strlen(uname) == 0)
+        return NULL;
+    
+    const char *duser = "${user}";
+    char *retptr = obuf;
+    const char *wiptr = proposed;
+    const char *findptr = strstr(proposed, uname);
+    if (findptr == NULL) {
+        return NULL;
+    }
+
+    // Copy leading before match
+    int segsize = findptr - wiptr;
+    int copysize = MIN(osize, segsize);
+    if (copysize)
+        strncpy(obuf, wiptr, copysize);
+    wiptr += copysize;
+    osize -= copysize;
+    obuf  += copysize;
+
+    // Copy the substitution string
+    segsize = strlen(duser);
+    copysize = MIN(osize, segsize);
+    if (copysize)
+        strncpy(obuf, duser, copysize);
+    wiptr += strlen(uname);
+    osize -= copysize;
+    obuf  += copysize;
+
+    // Copy trailing after match
+    strncpy(obuf, wiptr, osize);
+    return retptr;
+}
+
+
+//
+//
+// Size of 'easy' temporary copy of allowed input string
+#define QPALN_SIZE 1024
+// Size of user-name-substituted proposed string.
+#define QPALN_USERBUFSIZE 300
+// C in the CSV string
+#define QPALN_COMMA_SEP ","
+// Wildcard character
+#define QPALN_WILDCARD '*'
+
+bool _qd_policy_approve_link_name(const char *username, const char *allowed, const char *proposed)
+{
+    // Verify string sizes are usable
+    size_t p_len = strlen(proposed);
+    if (p_len == 0) {
+        // degenerate case of blank name being opened. will never match anything.
+        return false;
+    }
+    size_t a_len = strlen(allowed);
+    if (a_len == 0) {
+        // no names in 'allowed'.
+        return false;
+    }
+
+    // Create a temporary writable copy of incoming allowed list
+    char t_allow[QPALN_SIZE + 1]; // temporary buffer for normal allow lists
+    char * pa = t_allow;
+    if (a_len > QPALN_SIZE) {
+        pa = (char *)malloc(a_len + 1); // malloc a buffer for larger allow lists
+    }
+    strncpy(pa, allowed, a_len);
+    pa[a_len] = 0;
+    // Do reverse user substitution into proposed
+    char substbuf[QPALN_USERBUFSIZE];
+    char * prop2 = _qd_policy_link_user_name_subst(username, proposed, substbuf, QPALN_USERBUFSIZE);
+    char *tok, *toknext;
+    tok = strtok_r(pa, QPALN_COMMA_SEP, &toknext);
+    assert (tok);
+    bool result = false;
+    while (tok != NULL) {
+        if (*tok == QPALN_WILDCARD) {
+            result = true;
+            break;
+        }
+	int matchlen = p_len;
+        int len = strlen(tok);
+        if (tok[len-1] == QPALN_WILDCARD) {
+            matchlen = len - 1;
+            assert(len > 0);
+        }
+        if (strncmp(tok, proposed, matchlen) == 0) {
+            result = true;
+            break;
+        }
+        if (prop2 && strncmp(tok, prop2, matchlen) == 0) {
+            result = true;
+            break;
+        }
+        tok = strtok_r(NULL, QPALN_COMMA_SEP, &toknext);
+    }
+    if (pa != t_allow) {
+        free(pa);
+    }
+    return result;
+}
+
+//
+//
 bool qd_policy_approve_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_conn)
 {
     if (qd_conn->policy_settings->maxSenders) {

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/1aea48ed/src/policy_internal.h
----------------------------------------------------------------------
diff --git a/src/policy_internal.h b/src/policy_internal.h
new file mode 100644
index 0000000..1c00ab8
--- /dev/null
+++ b/src/policy_internal.h
@@ -0,0 +1,100 @@
+#ifndef __policy_internal_h__
+#define __policy_internal_h__
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "policy.h"
+
+/**
+ * Private Function Prototypes
+ */
+/** Set the error condition and close the connection.
+ * Over the wire this will send an open frame followed
+ * immediately by a close frame with the error condition.
+ * @param[in] conn proton connection being closed
+ * @param[in] cond_name condition name
+ * @param[in] cond_descr condition description
+ **/ 
+void qd_policy_private_deny_amqp_connection(pn_connection_t *conn, const char *cond_name, const char *cond_descr);
+
+
+/** Internal function to deny an amqp session
+ * The session is closed with a condition and the denial is logged and counted.
+ * @param[in,out] ssn proton session being closed
+ * @param[in,out] qd_conn dispatch connection
+ */
+void qd_policy_deny_amqp_session(pn_session_t *ssn, qd_connection_t *qd_conn);
+
+
+/** Internal function to deny an amqp link
+ * The link is closed and the denial is logged but not counted.
+ * @param[in] link proton link being closed
+ * @param[in] qd_conn the qd conection
+ * @param[in] s_or_r 'sender' or 'receiver' for logging
+ */ 
+void _qd_policy_deny_amqp_link(pn_link_t *link, qd_connection_t *qd_conn, char * s_or_r);
+
+
+/** Internal function to deny a sender amqp link
+ * The link is closed and the denial is logged but not counted.
+ * @param[in] link proton link to close
+ * @param[in] qd_conn the qd conection
+ * @param[in] s_or_r 'sender' or 'receiver' for logging
+ */ 
+void _qd_policy_deny_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_conn);
+
+
+/** Internal function to deny a receiver amqp link
+ * The link is closed and the denial is logged but not counted.
+ * @param[in] link proton link to close
+ * @param[in] qd_conn the qd conection
+ * @param[in] s_or_r 'sender' or 'receiver' for logging
+ */ 
+void _qd_policy_deny_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *qd_conn);
+
+
+/** Perform user name substitution into proposed link name.
+ * The scheme is to substitute '${user}' into the incoming link name whereever the
+ * the username is present. Then it can be matched against the original template with
+ * a minimum of substitutions. For example:
+ * uname    : joe
+ * proposed : temp_joe_1
+ * obuf     : temp_${user}_1
+ * Note: substituted names are limited to osize characters
+ *
+ * @param[in] uname auth user name
+ * @param[in] proposed the link name from the AMQP frame
+ * @param[out] obuf where the constructed link name is returned
+ * @param[in] osize size in bytes of obuf
+ * @return NULL if uname is not present in proposed link name.
+ */
+char * _qd_policy_link_user_name_subst(const char *uname, const char *proposed, char *obuf, int osize);
+
+
+/** Approve link by source/target name.
+ * This match supports trailing wildcard match:
+ *    proposed 'temp-305' matches allowed 'temp-*'
+ * This match supports username substitution:
+ *    user 'joe', proposed 'temp-joe' matches allowed 'temp-${user}'
+ * @param[in] username authenticated user name
+ * @param[in] allowed policy settings source/target string in packed CSV form.
+ * @param[in] proposed the link target name to be approved
+ */
+bool _qd_policy_approve_link_name(const char *username, const char *allowed, const char *proposed);
+#endif

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/1aea48ed/tests/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index e752c2a..c779b9a 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -28,6 +28,7 @@ include_directories(
 set(unit_test_SOURCES
     compose_test.c
     parse_test.c
+    policy_test.c
     run_unit_tests.c
     server_test.c
     timer_test.c

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/1aea48ed/tests/policy_test.c
----------------------------------------------------------------------
diff --git a/tests/policy_test.c b/tests/policy_test.c
new file mode 100644
index 0000000..0061169
--- /dev/null
+++ b/tests/policy_test.c
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_case.h"
+#include <stdio.h>
+#include <string.h>
+#include "policy.h"
+#include "policy_internal.h"
+
+static char *test_link_name_lookup(void *context)
+{
+    // Degenerate blank names
+    if (_qd_policy_approve_link_name("a", "a", ""))
+	return "blank proposed name not rejected";
+    if (_qd_policy_approve_link_name("a", "", "a"))
+	return "blank allowed list not rejected";
+
+    // Easy matches
+    if (!_qd_policy_approve_link_name("", "joe", "joe"))
+        return "proposed link 'joe' should match allowed links 'joe' but does not";
+    if (_qd_policy_approve_link_name("", "joe", "joey"))
+        return "proposed link 'joey' should not match allowed links 'joe' but does";
+
+    // Wildcard matches
+    if (!_qd_policy_approve_link_name("", "joe*", "joey"))
+        return "proposed link 'joey' should match allowed links 'joe*' but does not";
+    if (!_qd_policy_approve_link_name("", "joe*", "joezzzZZZ"))
+        return "proposed link 'joezzzZZZ' should match allowed links 'joe*' but does not";
+    if (!_qd_policy_approve_link_name("", "joe,*", "joey"))
+        return "proposed link 'joey' should match allowed links 'joe,*' but does not";
+
+    // Deeper match
+    if (!_qd_policy_approve_link_name("", "no1,no2,no3,yes,no4", "yes"))
+        return "proposed link 'yes' should match allowed links 'no1,no2,no3,yes,no4' but does not";
+
+    // Deeeper match - triggers malloc/free internal handler
+    char * bufp = (char *)malloc(512 * 5 + 6);
+    char * wp = bufp;
+    int i;
+    for (i=0; i<512; i++) {
+        wp += sprintf(wp, "n%03d,", i);
+    }
+    sprintf(wp, "yes");
+    if (!_qd_policy_approve_link_name("", bufp, "yes")) {
+        free(bufp);
+        return "proposed link 'yes' should match allowed large list but does not";
+    }
+    free(bufp);
+
+    // Substitute a user name
+    if (!_qd_policy_approve_link_name("chuck", "ab${user}xyz", "abchuckxyz"))
+        return "proposed link 'abchuckxyz' should match allowed links with ${user} but does not";
+    if (!_qd_policy_approve_link_name("chuck", "${user}xyz", "chuckxyz"))
+        return "proposed link 'chuckxyz' should match allowed links with ${user} but does not";
+    if (!_qd_policy_approve_link_name("chuck", "ab${user}", "abchuck"))
+        return "proposed link 'abchuck' should match allowed links with ${user} but does not";
+
+    // Combine user name and wildcard
+    if (!_qd_policy_approve_link_name("chuck", "ab${user}*", "abchuckzyxw"))
+        return "proposed link 'abchuckzyxw' should match allowed links with ${user}* but does not";
+    
+    return 0;
+}
+
+int policy_tests(void)
+{
+    int result = 0;
+
+    TEST_CASE(test_link_name_lookup, 0);
+
+    return result;
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-dispatch/blob/1aea48ed/tests/run_unit_tests.c
----------------------------------------------------------------------
diff --git a/tests/run_unit_tests.c b/tests/run_unit_tests.c
index d2e5571..df4fe56 100644
--- a/tests/run_unit_tests.c
+++ b/tests/run_unit_tests.c
@@ -29,6 +29,7 @@ int alloc_tests(void);
 int server_tests(qd_dispatch_t *qd);
 int parse_tests(void);
 int compose_tests(void);
+int policy_tests(void);
 
 int main(int argc, char** argv)
 {
@@ -53,6 +54,7 @@ int main(int argc, char** argv)
 #if USE_MEMORY_POOL
     result += alloc_tests();
 #endif
+    result += policy_tests();
     qd_dispatch_free(qd);       // dispatch_free last.
 
     return result;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org