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