You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2020/08/31 23:59:00 UTC

[qpid-proton] 01/03: PROTON-2234: Allow setting and retrieving SASL authzid on clients/servers

This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git

commit 51158fa5742b841f09ae5db5c517afc0c74356ec
Author: Andrew Stitcher <as...@apache.org>
AuthorDate: Tue Jul 14 18:15:14 2020 -0400

    PROTON-2234: Allow setting and retrieving SASL authzid on clients/servers
---
 c/include/proton/connection.h  | 25 +++++++++++++++++++++
 c/include/proton/sasl-plugin.h |  3 ++-
 c/include/proton/sasl.h        | 20 +++++++++++++++++
 c/src/core/engine-internal.h   |  1 +
 c/src/core/engine.c            | 14 ++++++++++++
 c/src/core/transport.c         |  7 ++++--
 c/src/sasl/cyrus_sasl.c        | 49 +++++++++++++++++++++++++++++++++++-------
 c/src/sasl/default_sasl.c      | 37 ++++++++++++++++++++++---------
 c/src/sasl/sasl-internal.h     |  3 ++-
 c/src/sasl/sasl.c              | 27 +++++++++++++++++++----
 10 files changed, 160 insertions(+), 26 deletions(-)

diff --git a/c/include/proton/connection.h b/c/include/proton/connection.h
index 9814828..73de72d 100644
--- a/c/include/proton/connection.h
+++ b/c/include/proton/connection.h
@@ -322,6 +322,23 @@ PN_EXTERN void pn_connection_set_user(pn_connection_t *connection, const char *u
 PN_EXTERN void pn_connection_set_password(pn_connection_t *connection, const char *password);
 
 /**
+ * Set the authorization id for a client connection
+ *
+ * It is necessary to set the authorization before binding the connection
+ * to a transport and it isn't allowed to change it after the binding.
+ *
+ * This is only useful if the negotiated sasl mechanism supports transporting an authorization id separate from
+ * the authentication user.
+ *
+ * By default all mechanisms will consider the requested authorization as identical to the authentication if it
+ * is not supplied.
+ *
+ * @param[in] connection the connection
+ * @param[in] authzid the authorization id
+ */
+PN_EXTERN void pn_connection_set_authorization(pn_connection_t *connection, const char *authzid);
+
+/**
  * Get the authentication username for a client connection
  *
  * @param[in] connection the connection
@@ -330,6 +347,14 @@ PN_EXTERN void pn_connection_set_password(pn_connection_t *connection, const cha
 PN_EXTERN const char *pn_connection_get_user(pn_connection_t *connection);
 
 /**
+ * Get the authorization id for a client connection
+ *
+ * @param[in] connection the connection
+ * @return the authorization passed into the connection
+ */
+PN_EXTERN const char *pn_connection_get_authorization(pn_connection_t *connection);
+
+/**
  * Get the value of the AMQP Hostname used by a connection object.
  *
  * The pointer returned by this operation is valid until
diff --git a/c/include/proton/sasl-plugin.h b/c/include/proton/sasl-plugin.h
index ae6b0ec..1269427 100644
--- a/c/include/proton/sasl-plugin.h
+++ b/c/include/proton/sasl-plugin.h
@@ -123,6 +123,7 @@ PN_EXTERN int   pnx_sasl_get_external_ssf(pn_transport_t *transport);
 
 PN_EXTERN const char *pnx_sasl_get_username(pn_transport_t *transport);
 PN_EXTERN const char *pnx_sasl_get_password(pn_transport_t *transport);
+PN_EXTERN const char *pnx_sasl_get_authorization(pn_transport_t *transport);
 PN_EXTERN void  pnx_sasl_clear_password(pn_transport_t *transport);
 PN_EXTERN const char *pnx_sasl_get_remote_fqdn(pn_transport_t *transport);
 PN_EXTERN const char *pnx_sasl_get_selected_mechanism(pn_transport_t *transport);
@@ -131,7 +132,7 @@ PN_EXTERN void  pnx_sasl_set_bytes_out(pn_transport_t *transport, pn_bytes_t byt
 PN_EXTERN void  pnx_sasl_set_desired_state(pn_transport_t *transport, enum pnx_sasl_state desired_state);
 PN_EXTERN void  pnx_sasl_set_selected_mechanism(pn_transport_t *transport, const char *mechanism);
 PN_EXTERN void  pnx_sasl_set_local_hostname(pn_transport_t * transport, const char * fqdn);
-PN_EXTERN void  pnx_sasl_succeed_authentication(pn_transport_t *transport, const char *username);
+PN_EXTERN void  pnx_sasl_succeed_authentication(pn_transport_t *transport, const char *username, const char *authzid);
 PN_EXTERN void  pnx_sasl_fail_authentication(pn_transport_t *transport);
 
 PN_EXTERN void  pnx_sasl_set_implementation(pn_transport_t *transport, const pnx_sasl_implementation *impl, void *context);
diff --git a/c/include/proton/sasl.h b/c/include/proton/sasl.h
index 251471e..906b0b3 100644
--- a/c/include/proton/sasl.h
+++ b/c/include/proton/sasl.h
@@ -125,6 +125,26 @@ PN_EXTERN pn_sasl_outcome_t pn_sasl_outcome(pn_sasl_t *sasl);
 PN_EXTERN const char *pn_sasl_get_user(pn_sasl_t *sasl);
 
 /**
+ * Retrieve the authorization id
+ *
+ * This is usually used at the the server end to find the name of the requested authorization id.
+ * On the client it will merely return whatever was passed in to the
+ * pn_transport_set_authorization() API.
+ *
+ * If pn_sasl_outcome() returns a value other than PN_SASL_OK, then there will be no user to return.
+ * The returned value is only reliable after the PN_TRANSPORT_AUTHENTICATED event has been received.
+ *
+ * @param[in] sasl the sasl layer
+ *
+ * @return
+ * If the SASL layer was not negotiated then 0 is returned
+ * If the ANONYMOUS mechanism is used then 0 is returned
+ * If no authorization id was requested then 0 is returned
+ * Otherwise a string containing the requested authorization id is returned.
+ */
+PN_EXTERN const char *pn_sasl_get_authorization(pn_sasl_t *sasl);
+
+/**
  * Return the selected SASL mechanism
  *
  * The returned value is only reliable after the PN_TRANSPORT_AUTHENTICATED event has been received.
diff --git a/c/src/core/engine-internal.h b/c/src/core/engine-internal.h
index 9dbc919..11718c9 100644
--- a/c/src/core/engine-internal.h
+++ b/c/src/core/engine-internal.h
@@ -243,6 +243,7 @@ struct pn_connection_t {
   pn_string_t *container;
   pn_string_t *hostname;
   pn_string_t *auth_user;
+  pn_string_t *authzid;
   pn_string_t *auth_password;
   pn_data_t *offered_capabilities;
   pn_data_t *desired_capabilities;
diff --git a/c/src/core/engine.c b/c/src/core/engine.c
index 8300e42..bfc8613 100644
--- a/c/src/core/engine.c
+++ b/c/src/core/engine.c
@@ -499,6 +499,7 @@ static void pn_connection_finalize(void *object)
   pn_free(conn->container);
   pn_free(conn->hostname);
   pn_free(conn->auth_user);
+  pn_free(conn->authzid);
   pn_free(conn->auth_password);
   pn_free(conn->offered_capabilities);
   pn_free(conn->desired_capabilities);
@@ -533,6 +534,7 @@ pn_connection_t *pn_connection()
   conn->container = pn_string(NULL);
   conn->hostname = pn_string(NULL);
   conn->auth_user = pn_string(NULL);
+  conn->authzid = pn_string(NULL);
   conn->auth_password = pn_string(NULL);
   conn->offered_capabilities = pn_data(0);
   conn->desired_capabilities = pn_data(0);
@@ -608,6 +610,18 @@ void pn_connection_set_user(pn_connection_t *connection, const char *user)
     pn_string_set(connection->auth_user, user);
 }
 
+const char *pn_connection_get_authorization(pn_connection_t *connection)
+{
+  assert(connection);
+  return pn_string_get(connection->authzid);
+}
+
+void pn_connection_set_authorization(pn_connection_t *connection, const char *authzid)
+{
+  assert(connection);
+  pn_string_set(connection->authzid, authzid);
+}
+
 void pn_connection_set_password(pn_connection_t *connection, const char *password)
 {
     assert(connection);
diff --git a/c/src/core/transport.c b/c/src/core/transport.c
index c2f1c05..fe6ebf1 100644
--- a/c/src/core/transport.c
+++ b/c/src/core/transport.c
@@ -695,9 +695,12 @@ int pn_transport_bind(pn_transport_t *transport, pn_connection_t *connection)
   pn_connection_bound(connection);
 
   // set the hostname/user/password
-  if (pn_string_size(connection->auth_user)) {
+  if (pn_string_size(connection->auth_user) || pn_string_size(connection->authzid)) {
     pn_sasl(transport);
-    pni_sasl_set_user_password(transport, pn_string_get(connection->auth_user), pn_string_get(connection->auth_password));
+    pni_sasl_set_user_password(transport,
+                               pn_string_get(connection->auth_user),
+                               pn_string_get(connection->authzid),
+                               pn_string_get(connection->auth_password));
   }
 
   if (pn_string_size(connection->hostname)) {
diff --git a/c/src/sasl/cyrus_sasl.c b/c/src/sasl/cyrus_sasl.c
index d98f3a3..fd189c0 100644
--- a/c/src/sasl/cyrus_sasl.c
+++ b/c/src/sasl/cyrus_sasl.c
@@ -118,7 +118,12 @@ static void pni_cyrus_interact(pn_transport_t *transport, sasl_interact_t *inter
 {
   for (sasl_interact_t *i = interact; i->id!=SASL_CB_LIST_END; i++) {
     switch (i->id) {
-    case SASL_CB_USER:
+    case SASL_CB_USER: {
+      const char *authzid = pnx_sasl_get_authorization(transport);
+      i->result = authzid;
+      i->len = authzid ? strlen(authzid) : 0;
+      break;
+    }
     case SASL_CB_AUTHNAME: {
       const char *username = pnx_sasl_get_username(transport);
       i->result = username;
@@ -158,8 +163,32 @@ static const sasl_callback_t pni_user_password_callbacks[] = {
 };
 
 static const sasl_callback_t pni_user_callbacks[] = {
-    {SASL_CB_USER, NULL, NULL},
-    {SASL_CB_AUTHNAME, NULL, NULL},
+  {SASL_CB_USER, NULL, NULL},
+  {SASL_CB_AUTHNAME, NULL, NULL},
+  {SASL_CB_LIST_END, NULL, NULL},
+};
+
+static const sasl_callback_t pni_authzid_callbacks[] = {
+  {SASL_CB_USER, NULL, NULL},
+  {SASL_CB_LIST_END, NULL, NULL},
+};
+
+static int pni_authorize(sasl_conn_t *conn,
+    void *context,
+    const char *requested_user, unsigned rlen,
+    const char *auth_identity, unsigned alen,
+    const char *def_realm, unsigned urlen,
+    struct propctx *propctx)
+{
+  PN_LOG_DEFAULT(PN_SUBSYSTEM_SASL, PN_LEVEL_TRACE, "Authorized: userid=%*s by authuser=%*s @ %*s",
+    rlen, requested_user,
+    alen, auth_identity,
+    urlen, def_realm);
+  return SASL_OK;
+}
+
+static const sasl_callback_t pni_server_callbacks[] = {
+    {SASL_CB_PROXY_POLICY, (int(*)(void)) pni_authorize, NULL},
     {SASL_CB_LIST_END, NULL, NULL},
 };
 
@@ -234,7 +263,7 @@ static void pni_cyrus_server_once(void) {
     }
   }
   if (result==SASL_OK) {
-    result = sasl_server_init(NULL, pni_cyrus_config_name ? pni_cyrus_config_name : default_config_name);
+    result = sasl_server_init(pni_server_callbacks, pni_cyrus_config_name ? pni_cyrus_config_name : default_config_name);
   }
   pni_cyrus_server_started = true;
   pni_cyrus_server_init_rc = result;
@@ -263,7 +292,8 @@ bool cyrus_sasl_init_client(pn_transport_t* transport) {
     if (result!=SASL_OK) break;
 
     const sasl_callback_t *callbacks =
-      pnx_sasl_get_username(transport) ? pnx_sasl_get_password(transport) ? pni_user_password_callbacks : pni_user_callbacks : NULL;
+      pnx_sasl_get_username(transport) ? (pnx_sasl_get_password(transport) ? pni_user_password_callbacks : pni_user_callbacks) :
+      pnx_sasl_get_authorization(transport) ? pni_authzid_callbacks : NULL;
     result = sasl_client_new(amqp_service,
                              pnx_sasl_get_remote_fqdn(transport),
                              NULL, NULL,
@@ -466,9 +496,12 @@ static void pni_process_server_result(pn_transport_t *transport, int result)
         case SASL_OK: {
             // Authenticated
             // Get username from SASL
-            const void* value;
-            sasl_getprop(cyrus_conn, SASL_USERNAME, &value);
-            pnx_sasl_succeed_authentication(transport, (const char*) value);
+            const void* authcid;
+            sasl_getprop(cyrus_conn, SASL_AUTHUSER, &authcid);
+            // Get authzid from SASL
+            const void* authzid;
+            sasl_getprop(cyrus_conn, SASL_USERNAME, &authzid);
+            pnx_sasl_succeed_authentication(transport, (const char*) authcid, (const char*) authzid);
             pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
             break;
         }
diff --git a/c/src/sasl/default_sasl.c b/c/src/sasl/default_sasl.c
index 7299318..287bf06 100644
--- a/c/src/sasl/default_sasl.c
+++ b/c/src/sasl/default_sasl.c
@@ -98,6 +98,7 @@ bool default_sasl_process_mechanisms(pn_transport_t *transport, const char *mech
 {
   const char *username = pnx_sasl_get_username(transport);
   const char *password = pnx_sasl_get_password(transport);
+  const char *authzid  = pnx_sasl_get_authorization(transport);
 
   // Check whether offered EXTERNAL, PLAIN or ANONYMOUS
   // Look for "EXTERNAL" in mechs
@@ -105,14 +106,14 @@ bool default_sasl_process_mechanisms(pn_transport_t *transport, const char *mech
   // Make sure that string is separated and terminated
   if (found && (found==mechs || found[-1]==' ') && (found[8]==0 || found[8]==' ')) {
     pnx_sasl_set_selected_mechanism(transport, EXTERNAL);
-    if (username) {
-      size_t size = strlen(username);
+    if (authzid) {
+      size_t size = strlen(authzid);
       char *iresp = (char *) malloc(size);
       if (!iresp) return false;
 
       pnx_sasl_set_context(transport, iresp);
 
-      memmove(iresp, username, size);
+      memmove(iresp, authzid, size);
       pnx_sasl_set_bytes_out(transport, pn_bytes(size, iresp));
     } else {
       static const char empty[] = "";
@@ -130,18 +131,20 @@ bool default_sasl_process_mechanisms(pn_transport_t *transport, const char *mech
       (pnx_sasl_is_transport_encrypted(transport) || pnx_sasl_get_allow_insecure_mechs(transport)) &&
       username && password) {
     pnx_sasl_set_selected_mechanism(transport, PLAIN);
+    size_t zsize = authzid ? strlen(authzid) : 0;
     size_t usize = strlen(username);
     size_t psize = strlen(password);
-    size_t size = usize + psize + 2;
+    size_t size = zsize + usize + psize + 2;
     char *iresp = (char *) malloc(size);
     if (!iresp) return false;
 
     pnx_sasl_set_context(transport, iresp);
 
-    iresp[0] = 0;
-    memmove(&iresp[1], username, usize);
-    iresp[usize + 1] = 0;
-    memmove(&iresp[usize + 2], password, psize);
+    if (authzid) memmove(&iresp[0], authzid, zsize);
+    iresp[zsize] = 0;
+    memmove(&iresp[zsize + 1], username, usize);
+    iresp[zsize + usize + 1] = 0;
+    memmove(&iresp[zsize + usize + 2], password, psize);
     pnx_sasl_set_bytes_out(transport, pn_bytes(size, iresp));
 
     // Zero out password and dealloc
@@ -191,7 +194,7 @@ void default_sasl_process_init(pn_transport_t *transport, const char *mechanism,
 {
   // Check that mechanism is ANONYMOUS
   if (strcmp(mechanism, ANONYMOUS)==0) {
-    pnx_sasl_succeed_authentication(transport, "anonymous");
+    pnx_sasl_succeed_authentication(transport, "anonymous", "anonymous");
     pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
     return;
   }
@@ -199,7 +202,21 @@ void default_sasl_process_init(pn_transport_t *transport, const char *mechanism,
   // Or maybe EXTERNAL
   const char *ext_username = pnx_sasl_get_external_username(transport);
   if (strcmp(mechanism, EXTERNAL)==0 && ext_username) {
-    pnx_sasl_succeed_authentication(transport, ext_username);
+
+    char *authzid = NULL;
+
+    if (recv->size) {
+      authzid = (char *) malloc(recv->size+1);
+      pnx_sasl_set_context(transport, authzid);
+
+      // If we didn't get memory pretend no authzid
+      if (authzid) {
+        memcpy(&authzid[0], recv->start, recv->size);
+        authzid[recv->size] = 0;
+      }
+    }
+
+    pnx_sasl_succeed_authentication(transport, ext_username, authzid ? authzid : ext_username);
     pnx_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
     return;
   }
diff --git a/c/src/sasl/sasl-internal.h b/c/src/sasl/sasl-internal.h
index aade2e0..82ff85a 100644
--- a/c/src/sasl/sasl-internal.h
+++ b/c/src/sasl/sasl-internal.h
@@ -34,7 +34,7 @@ extern const pnx_sasl_implementation * const cyrus_sasl_impl;
 
 // SASL APIs used by transport code
 void pn_sasl_free(pn_transport_t *transport);
-void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password);
+void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *authzid, const char *password);
 void pni_sasl_set_remote_hostname(pn_transport_t *transport, const char* fqdn);
 void pni_sasl_set_external_security(pn_transport_t *transport, int ssf, const char *authid);
 
@@ -44,6 +44,7 @@ struct pni_sasl_t {
   char *selected_mechanism;
   char *included_mechanisms;
   const char *username;
+  const char *authzid;
   char *password;
   const char *remote_fqdn;
   char *local_fqdn;
diff --git a/c/src/sasl/sasl.c b/c/src/sasl/sasl.c
index b901e9f..500b286 100644
--- a/c/src/sasl/sasl.c
+++ b/c/src/sasl/sasl.c
@@ -95,6 +95,11 @@ const char *pnx_sasl_get_username(pn_transport_t *transport)
   return transport->sasl ? transport->sasl->username : NULL;
 }
 
+const char *pnx_sasl_get_authorization(pn_transport_t *transport)
+{
+  return transport->sasl ? transport->sasl->authzid : NULL;
+}
+
 const char *pnx_sasl_get_external_username(pn_transport_t *transport)
 {
   return transport->sasl ? transport->sasl->external_auth : NULL;
@@ -143,15 +148,21 @@ void  pnx_sasl_set_selected_mechanism(pn_transport_t *transport, const char *mec
   }
 }
 
-void  pnx_sasl_succeed_authentication(pn_transport_t *transport, const char *username)
+void  pnx_sasl_succeed_authentication(pn_transport_t *transport, const char *username, const char *authzid)
 {
   if (transport->sasl) {
     transport->sasl->username = username;
+    transport->sasl->authzid = authzid;
     transport->sasl->outcome = PN_SASL_OK;
     transport->authenticated = true;
 
-    PN_LOG(&transport->logger, PN_SUBSYSTEM_SASL, PN_LEVEL_INFO, "Authenticated user: %s with mechanism %s",
-                  username, transport->sasl->selected_mechanism);
+    if (authzid) {
+      PN_LOG(&transport->logger, PN_SUBSYSTEM_SASL, PN_LEVEL_INFO, "Authenticated user: %s for %s with mechanism %s",
+             username, authzid, transport->sasl->selected_mechanism);
+    } else {
+      PN_LOG(&transport->logger, PN_SUBSYSTEM_SASL, PN_LEVEL_INFO, "Authenticated user: %s with mechanism %s",
+             username, transport->sasl->selected_mechanism);
+    }
   }
 }
 
@@ -729,6 +740,7 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport)
     sasl->selected_mechanism = NULL;
     sasl->included_mechanisms = NULL;
     sasl->username = NULL;
+    sasl->authzid = NULL;
     sasl->password = NULL;
     sasl->remote_fqdn = NULL;
     sasl->local_fqdn = NULL;
@@ -783,10 +795,11 @@ void pnx_sasl_set_local_hostname(pn_transport_t * transport, const char * fqdn)
   sasl->local_fqdn = pn_strdup(fqdn);
 }
 
-void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password)
+void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *authzid, const char *password)
 {
   pni_sasl_t *sasl = transport->sasl;
   sasl->username = user;
+  sasl->authzid = authzid;
   free(sasl->password);
   sasl->password = password ? pn_strdup(password) : NULL;
 }
@@ -805,6 +818,12 @@ const char *pn_sasl_get_user(pn_sasl_t *sasl0)
     return sasl->username;
 }
 
+const char *pn_sasl_get_authorization(pn_sasl_t *sasl0)
+{
+    pni_sasl_t *sasl = get_sasl_internal(sasl0);
+    return sasl->authzid;
+}
+
 const char *pn_sasl_get_mech(pn_sasl_t *sasl0)
 {
     pni_sasl_t *sasl = get_sasl_internal(sasl0);


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