WIP: a sasl implementation that delegates to a remote authentication service, 
using AMQP SASL frame relaying


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/4894265b
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/4894265b
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/4894265b

Branch: refs/heads/PROTON-1488
Commit: 4894265b3d1517f62265907000dfc948cbb1c75d
Parents: d652405
Author: Gordon Sim <g...@redhat.com>
Authored: Wed May 17 16:19:47 2017 +0100
Committer: Gordon Sim <g...@redhat.com>
Committed: Thu May 25 14:44:45 2017 +0100

----------------------------------------------------------------------
 proton-c/CMakeLists.txt            |   4 +-
 proton-c/include/proton/proactor.h |   2 +
 proton-c/src/core/util.h           |   2 +-
 proton-c/src/sasl/cyrus_sasl.c     |   9 +-
 proton-c/src/sasl/none_sasl.c      |   5 +
 proton-c/src/sasl/remote_sasl.c    | 271 ++++++++++++++++++++++++++++++++
 proton-c/src/sasl/sasl-internal.h  |  23 ++-
 proton-c/src/sasl/sasl.c           | 122 +++++++++++---
 8 files changed, 414 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 33933b8..094fba4 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -486,7 +486,7 @@ if (PROACTOR STREQUAL "epoll" OR (NOT PROACTOR AND NOT 
BUILD_PROACTOR))
   check_symbol_exists(epoll_wait "sys/epoll.h" HAVE_EPOLL)
   if (HAVE_EPOLL)
     set (PROACTOR_OK epoll)
-    set (qpid-proton-proactor src/proactor/epoll.c 
src/proactor/proactor-internal.c)
+    set (qpid-proton-proactor src/proactor/epoll.c 
src/proactor/proactor-internal.c src/sasl/remote_sasl.c)
     set (PROACTOR_LIBS -lpthread)
     set_source_files_properties (${qpid-proton-proactor} PROPERTIES
       COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LTO}"
@@ -498,7 +498,7 @@ if (PROACTOR STREQUAL "libuv" OR (NOT PROACTOR AND NOT 
PROACTOR_OK))
   find_package(Libuv)
   if (LIBUV_FOUND)
     set (PROACTOR_OK libuv)
-    set (qpid-proton-proactor src/proactor/libuv.c 
src/proactor/proactor-internal.c)
+    set (qpid-proton-proactor src/proactor/libuv.c 
src/proactor/proactor-internal.c src/sasl/remote_sasl.c)
     set (PROACTOR_LIBS ${Libuv_LIBRARIES})
     set_source_files_properties (${qpid-proton-proactor} PROPERTIES
       COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LTO}"

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/include/proton/proactor.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/proactor.h 
b/proton-c/include/proton/proactor.h
index 861afbe..5dd16f9 100644
--- a/proton-c/include/proton/proactor.h
+++ b/proton-c/include/proton/proactor.h
@@ -285,6 +285,8 @@ PNP_EXTERN pn_proactor_t *pn_event_proactor(pn_event_t 
*event);
  */
 PNP_EXTERN pn_millis_t pn_proactor_now(void);
 
+PNP_EXTERN void pn_use_remote_authentication_service(const char* address);
+
 /**
  * @defgroup proactor_events Events
  *

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/src/core/util.h
----------------------------------------------------------------------
diff --git a/proton-c/src/core/util.h b/proton-c/src/core/util.h
index 4d3ba3b..ee83f90 100644
--- a/proton-c/src/core/util.h
+++ b/proton-c/src/core/util.h
@@ -39,7 +39,7 @@ void pn_print_data(const char *bytes, size_t size);
 bool pn_env_bool(const char *name);
 pn_timestamp_t pn_timestamp_min(pn_timestamp_t a, pn_timestamp_t b);
 
-char *pn_strdup(const char *src);
+PN_EXTERN char *pn_strdup(const char *src);
 char *pn_strndup(const char *src, size_t n);
 int pn_strcasecmp(const char* a, const char* b);
 int pn_strncasecmp(const char* a, const char* b, size_t len);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/src/sasl/cyrus_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/cyrus_sasl.c b/proton-c/src/sasl/cyrus_sasl.c
index ef1db9d..74e124f 100644
--- a/proton-c/src/sasl/cyrus_sasl.c
+++ b/proton-c/src/sasl/cyrus_sasl.c
@@ -247,6 +247,7 @@ bool pni_process_mechanisms(pn_transport_t *transport, 
const char *mechs)
         case SASL_OK:
         case SASL_CONTINUE:
           sasl->selected_mechanism = pn_strdup(mech_selected);
+          pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
           return true;
         case SASL_NOMECH:
         default:
@@ -350,7 +351,13 @@ bool pni_init_server(pn_transport_t* transport)
     }
   } while (false);
   cyrus_conn = (sasl_conn_t*) sasl->impl_context;
-  return pni_check_sasl_result(cyrus_conn, result, transport);
+  if (pni_check_sasl_result(cyrus_conn, result, transport)) {
+      // Setup to send SASL mechanisms frame
+      pni_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
+      return true;
+  } else {
+      return false;
+  }
 }
 
 static int pni_wrap_server_start(pni_sasl_t *sasl, const char *mech_selected, 
const pn_bytes_t *in)

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/src/sasl/none_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/none_sasl.c b/proton-c/src/sasl/none_sasl.c
index 0408a8f..84a6640 100644
--- a/proton-c/src/sasl/none_sasl.c
+++ b/proton-c/src/sasl/none_sasl.c
@@ -29,6 +29,8 @@ static const char PLAIN[] = "PLAIN";
 
 bool pni_init_server(pn_transport_t* transport)
 {
+  // Setup to send SASL mechanisms frame
+  pni_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
   return true;
 }
 
@@ -67,6 +69,7 @@ bool pni_process_mechanisms(pn_transport_t *transport, const 
char *mechs)
       transport->sasl->bytes_out.start = empty;
       transport->sasl->bytes_out.size =  0;
     }
+    pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
     return true;
   }
 
@@ -98,6 +101,7 @@ bool pni_process_mechanisms(pn_transport_t *transport, const 
char *mechs)
     free(memset(transport->sasl->password, 0, psize));
     transport->sasl->password = NULL;
 
+    pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
     return true;
   }
 
@@ -122,6 +126,7 @@ bool pni_process_mechanisms(pn_transport_t *transport, 
const char *mechs)
       transport->sasl->bytes_out.start = anon;
       transport->sasl->bytes_out.size =  sizeof anon-1;
     }
+    pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
     return true;
   }
   return false;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/src/sasl/remote_sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/remote_sasl.c b/proton-c/src/sasl/remote_sasl.c
new file mode 100644
index 0000000..9ef3484
--- /dev/null
+++ b/proton-c/src/sasl/remote_sasl.c
@@ -0,0 +1,271 @@
+/*
+ *
+ * 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 "sasl-internal.h"
+
+#include "core/engine-internal.h"
+#include "core/util.h"
+#include "proton/proactor.h"
+
+typedef struct
+{
+    size_t size;
+    char *start;
+} pni_owned_bytes_t;
+
+const int8_t UPSTREAM_INIT_RECEIVED = 1;
+const int8_t UPSTREAM_RESPONSE_RECEIVED = 2;
+const int8_t DOWNSTREAM_MECHANISMS_RECEIVED = 3;
+const int8_t DOWNSTREAM_CHALLENGE_RECEIVED = 4;
+const int8_t DOWNSTREAM_OUTCOME_RECEIVED = 5;
+
+const char* authentication_service_address = NULL;
+
+typedef struct
+{
+    pn_connection_t* downstream;
+    char* selected_mechanism;
+    pni_owned_bytes_t response;
+    int8_t downstream_state;
+
+    pn_connection_t* upstream;
+    char* mechlist;
+    pni_owned_bytes_t challenge;
+    int8_t upstream_state;
+
+    pn_sasl_outcome_t outcome;
+    int refcount;
+} pni_sasl_relay_t;
+
+void pni_copy_bytes(const pn_bytes_t* from, pni_owned_bytes_t* to)
+{
+    if (to->start) {
+        free(to->start);
+    }
+    to->start = (char*) malloc(from->size);
+    to->size = from->size;
+    memcpy(to->start, from->start, from->size);
+}
+
+pni_sasl_relay_t* new_pni_sasl_relay_t(void)
+{
+    pni_sasl_relay_t* instance = (pni_sasl_relay_t*) 
malloc(sizeof(pni_sasl_relay_t));
+    instance->selected_mechanism = 0;
+    instance->response.start = 0;
+    instance->response.size = 0;
+    instance->mechlist = 0;
+    instance->challenge.start = 0;
+    instance->challenge.size = 0;
+    instance->refcount = 1;
+    instance->upstream_state = 0;
+    instance->downstream_state = 0;
+    return instance;
+}
+
+void delete_pni_sasl_relay_t(pni_sasl_relay_t* instance)
+{
+    if (instance->mechlist) free(instance->mechlist);
+    if (instance->selected_mechanism) free(instance->selected_mechanism);
+    if (instance->response.start) free(instance->response.start);
+    if (instance->challenge.start) free(instance->challenge.start);
+    free(instance);
+}
+
+void release_pni_sasl_relay_t(pni_sasl_relay_t* instance)
+{
+    if (instance && --(instance->refcount) == 0) {
+        delete_pni_sasl_relay_t(instance);
+    }
+}
+
+bool remote_init_server(pn_transport_t* transport)
+{
+    pn_connection_t* upstream = pn_transport_connection(transport);
+    if (upstream) {
+        if (transport->sasl->impl_context) {
+            return true;
+        }
+        pni_sasl_relay_t* impl = new_pni_sasl_relay_t();
+        transport->sasl->impl_context = impl;
+        impl->upstream = upstream;
+        pn_proactor_t* proactor = pn_connection_proactor(upstream);
+        if (!proactor) return false;
+        impl->downstream = pn_connection();
+        pn_connection_set_hostname(impl->downstream, 
pn_connection_get_hostname(upstream));
+        //do I need to explicitly set up sasl? if so how? need to handle 
connection_bound?
+        //for now just fake it with dummy user
+        pn_connection_set_user(impl->downstream, "dummy");
+        pn_connection_set_context(impl->downstream, 
transport->sasl->impl_context);//TODO: use record?
+
+        pn_proactor_connect(proactor, impl->downstream, 
authentication_service_address);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool remote_init_client(pn_transport_t* transport)
+{
+    //for the client side of the connection to the authentication
+    //service, need to use the same context as the server side of the
+    //connection it is authenticating on behalf of
+    pn_connection_t* conn = pn_transport_connection(transport);
+    transport->sasl->impl_context = pn_connection_get_context(conn);
+    ((pni_sasl_relay_t*) transport->sasl->impl_context)->refcount++;
+    return true;
+}
+
+bool remote_free(pn_transport_t *transport)
+{
+    if (transport->sasl->impl_context) {
+        release_pni_sasl_relay_t((pni_sasl_relay_t*) 
transport->sasl->impl_context);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+bool remote_prepare(pn_transport_t *transport)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (!impl) return false;
+    if (transport->sasl->client) {
+        if (impl->downstream_state == UPSTREAM_INIT_RECEIVED) {
+            transport->sasl->selected_mechanism = impl->selected_mechanism;
+            transport->sasl->bytes_out.start = impl->response.start;
+            transport->sasl->bytes_out.size = impl->response.size;
+            pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
+        } else if (impl->downstream_state == UPSTREAM_RESPONSE_RECEIVED) {
+            transport->sasl->bytes_out.start = impl->response.start;
+            transport->sasl->bytes_out.size = impl->response.size;
+            pni_sasl_set_desired_state(transport, SASL_POSTED_RESPONSE);
+        }
+        impl->downstream_state = 0;
+    } else {
+        if (impl->upstream_state == DOWNSTREAM_MECHANISMS_RECEIVED) {
+            pni_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
+        } else if (impl->upstream_state == DOWNSTREAM_CHALLENGE_RECEIVED) {
+            transport->sasl->bytes_out.start = impl->challenge.start;
+            transport->sasl->bytes_out.size = impl->challenge.size;
+            pni_sasl_set_desired_state(transport, SASL_POSTED_CHALLENGE);
+        } else if (impl->upstream_state == DOWNSTREAM_OUTCOME_RECEIVED) {
+            transport->sasl->outcome = impl->outcome;
+            pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
+        }
+        impl->upstream_state = 0;
+    }
+    return true;
+}
+
+// Client / Downstream
+bool remote_process_mechanisms(pn_transport_t *transport, const char *mechs)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (impl) {
+        if (impl->upstream_state != DOWNSTREAM_MECHANISMS_RECEIVED) {
+            impl->mechlist = pn_strdup(mechs);
+            impl->upstream_state = DOWNSTREAM_MECHANISMS_RECEIVED;
+            pn_connection_wake(impl->upstream);
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+// Client / Downstream
+void remote_process_challenge(pn_transport_t *transport, const pn_bytes_t 
*recv)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (impl && impl->upstream_state != DOWNSTREAM_CHALLENGE_RECEIVED) {
+        pni_copy_bytes(recv, &(impl->challenge));
+        impl->upstream_state = DOWNSTREAM_CHALLENGE_RECEIVED;
+        pn_connection_wake(impl->upstream);
+    }
+}
+
+// Client / Downstream
+bool remote_process_outcome(pn_transport_t *transport)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (impl) {
+        if (impl->upstream_state != DOWNSTREAM_OUTCOME_RECEIVED) {
+            impl->outcome = transport->sasl->outcome;
+            impl->upstream_state = DOWNSTREAM_OUTCOME_RECEIVED;
+            pn_connection_wake(impl->upstream);
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
+// Server / Upstream
+int remote_get_mechs(pn_transport_t *transport, char **mechlist)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (impl && impl->mechlist) {
+        *mechlist = pn_strdup(impl->mechlist);
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+// Server / Upstream
+void remote_process_init(pn_transport_t *transport, const char *mechanism, 
const pn_bytes_t *recv)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (impl) {
+        impl->selected_mechanism = pn_strdup(mechanism);
+        pni_copy_bytes(recv, &(impl->response));
+        impl->downstream_state = UPSTREAM_INIT_RECEIVED;
+        pn_connection_wake(impl->downstream);
+    }
+}
+
+// Server / Upstream
+void remote_process_response(pn_transport_t *transport, const pn_bytes_t *recv)
+{
+    pni_sasl_relay_t* impl = (pni_sasl_relay_t*) transport->sasl->impl_context;
+    if (impl) {
+        pni_copy_bytes(recv, &(impl->response));
+        impl->downstream_state = UPSTREAM_RESPONSE_RECEIVED;
+        pn_connection_wake(impl->downstream);
+    }
+}
+
+void pn_use_remote_authentication_service(const char* address)
+{
+    authentication_service_address = address;
+    pni_sasl_implementation remote_impl;
+    remote_impl.free = &remote_free;
+    remote_impl.get_mechs = &remote_get_mechs;
+    remote_impl.init_server = &remote_init_server;
+    remote_impl.process_init = &remote_process_init;
+    remote_impl.process_response = &remote_process_response;
+    remote_impl.init_client = &remote_init_client;
+    remote_impl.process_mechanisms = &remote_process_mechanisms;
+    remote_impl.process_challenge = &remote_process_challenge;
+    remote_impl.process_outcome = &remote_process_outcome;
+    remote_impl.prepare = &remote_prepare;
+    pni_sasl_set_implementation(remote_impl);
+}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/src/sasl/sasl-internal.h
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl-internal.h 
b/proton-c/src/sasl/sasl-internal.h
index 2873777..8fef243 100644
--- a/proton-c/src/sasl/sasl-internal.h
+++ b/proton-c/src/sasl/sasl-internal.h
@@ -52,6 +52,27 @@ ssize_t pni_sasl_impl_max_encrypt_size(pn_transport_t 
*transport);
 ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, 
pn_bytes_t *out);
 ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, 
pn_bytes_t *out);
 
+typedef bool (*pni_sasl_function)(pn_transport_t *transport);
+typedef void (*pni_sasl_challenge_response)(pn_transport_t *transport, const 
pn_bytes_t *recv);
+typedef void (*pni_sasl_init)(pn_transport_t *transport, const char 
*mechanism, const pn_bytes_t *recv);
+typedef bool (*pni_sasl_set_mechanisms)(pn_transport_t *transport, const char 
*mechanism);
+typedef int (*pni_sasl_get_mechanisms)(pn_transport_t *transport, char 
**mechlist);
+
+typedef struct
+{
+    pni_sasl_function free;
+    pni_sasl_get_mechanisms get_mechs;
+    pni_sasl_function init_server;
+    pni_sasl_init process_init;
+    pni_sasl_challenge_response process_response;
+    pni_sasl_function init_client;
+    pni_sasl_set_mechanisms process_mechanisms;
+    pni_sasl_challenge_response process_challenge;
+    pni_sasl_function process_outcome;
+    pni_sasl_function prepare;
+} pni_sasl_implementation;
+
+PN_EXTERN void pni_sasl_set_implementation(pni_sasl_implementation);
 
 // Shared SASL API used by the actual SASL authenticators
 enum pni_sasl_state {
@@ -91,6 +112,6 @@ struct pni_sasl_t {
 // Shared Utility used by sasl implementations
 void pni_split_mechs(char *mechlist, const char* included_mechs, char 
*mechs[], int *count);
 bool pni_included_mech(const char *included_mech_list, pn_bytes_t s);
-void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state 
desired_state);
+PN_EXTERN void pni_sasl_set_desired_state(pn_transport_t *transport, enum 
pni_sasl_state desired_state);
 
 #endif /* sasl-internal.h */

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/4894265b/proton-c/src/sasl/sasl.c
----------------------------------------------------------------------
diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c
index 55c489d..dcdcd17 100644
--- a/proton-c/src/sasl/sasl.c
+++ b/proton-c/src/sasl/sasl.c
@@ -136,6 +136,85 @@ static void pni_emit(pn_transport_t *transport)
   }
 }
 
+static pni_sasl_implementation* implementation = 0;
+
+void pni_sasl_set_implementation(pni_sasl_implementation i)
+{
+  implementation = (pni_sasl_implementation*) 
malloc(sizeof(pni_sasl_implementation));
+  *implementation = i;
+}
+
+void pni_sasl_impl_free_(pn_transport_t *transport)
+{
+  if (implementation) {
+    implementation->free(transport);
+  } else {
+    pni_sasl_impl_free(transport);
+  }
+}
+
+int  pni_sasl_impl_list_mechs_(pn_transport_t *transport, char **mechlist)
+{
+  if (implementation) {
+      return implementation->get_mechs(transport, mechlist);
+  } else {
+      return pni_sasl_impl_list_mechs(transport, mechlist);
+  }
+}
+
+bool pni_init_server_(pn_transport_t *transport)
+{
+  if (implementation) {
+    return implementation->init_server(transport);
+  } else {
+    return pni_init_server(transport);
+  }
+}
+
+void pni_process_init_(pn_transport_t *transport, const char *mechanism, const 
pn_bytes_t *recv)
+{
+  if (implementation) {
+    implementation->process_init(transport, mechanism, recv);
+  } else {
+    pni_process_init(transport, mechanism, recv);
+  }
+}
+
+void pni_process_response_(pn_transport_t *transport, const pn_bytes_t *recv)
+{
+  if (implementation) {
+      implementation->process_response(transport, recv);
+  } else {
+      pni_process_response(transport, recv);
+  }
+}
+
+bool pni_init_client_(pn_transport_t *transport)
+{
+  if (implementation) {
+    return implementation->init_client(transport);
+  } else {
+    return pni_init_client(transport);
+  }
+}
+bool pni_process_mechanisms_(pn_transport_t *transport, const char *mechs)
+{
+  if (implementation) {
+    return implementation->process_mechanisms(transport, mechs);
+  } else {
+    return pni_process_mechanisms(transport, mechs);
+  }
+}
+
+void pni_process_challenge_(pn_transport_t *transport, const pn_bytes_t *recv)
+{
+  if (implementation) {
+    implementation->process_challenge(transport, recv);
+  } else {
+    pni_process_challenge(transport, recv);
+  }
+}
+
 void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state 
desired_state)
 {
   pni_sasl_t *sasl = transport->sasl;
@@ -157,9 +236,10 @@ void pni_sasl_set_desired_state(pn_transport_t *transport, 
enum pni_sasl_state d
     if (sasl->last_state==desired_state && 
desired_state==SASL_POSTED_CHALLENGE) {
       sasl->last_state = SASL_POSTED_MECHANISMS;
     }
+    bool changed = sasl->desired_state != desired_state;
     sasl->desired_state = desired_state;
     // Don't emit transport event on error as there will be a TRANSPORT_ERROR 
event
-    if (desired_state != SASL_ERROR) pni_emit(transport);
+    if (desired_state != SASL_ERROR && changed) pni_emit(transport);
   }
 }
 
@@ -182,7 +262,7 @@ static void pni_post_sasl_frame(pn_transport_t *transport)
       char *mechlist = NULL;
 
       int count = 0;
-      if (pni_sasl_impl_list_mechs(transport, &mechlist) > 0) {
+      if (pni_sasl_impl_list_mechs_(transport, &mechlist) > 0) {
         pni_split_mechs(mechlist, sasl->included_mechanisms, mechs, &count);
       }
 
@@ -192,16 +272,19 @@ static void pni_post_sasl_frame(pn_transport_t *transport)
       break;
     }
     case SASL_POSTED_RESPONSE:
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_RESPONSE, 
out.size, out.start);
-      pni_emit(transport);
+      if (sasl->last_state != SASL_POSTED_RESPONSE) {
+          pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_RESPONSE, 
out.size, out.start);
+          pni_emit(transport);
+      }
       break;
     case SASL_POSTED_CHALLENGE:
       if (sasl->last_state < SASL_POSTED_MECHANISMS) {
         desired_state = SASL_POSTED_MECHANISMS;
         continue;
+      } else if (sasl->last_state != SASL_POSTED_CHALLENGE) {
+          pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", 
SASL_CHALLENGE, out.size, out.start);
+          pni_emit(transport);
       }
-      pn_post_frame(transport, SASL_FRAME_TYPE, 0, "DL[z]", SASL_CHALLENGE, 
out.size, out.start);
-      pni_emit(transport);
       break;
     case SASL_POSTED_OUTCOME:
       if (sasl->last_state < SASL_POSTED_MECHANISMS) {
@@ -277,10 +360,7 @@ static void pni_sasl_start_server_if_needed(pn_transport_t 
*transport)
 {
   pni_sasl_t *sasl = transport->sasl;
   if (!sasl->client && sasl->desired_state<SASL_POSTED_MECHANISMS) {
-    if (!pni_init_server(transport)) return;
-
-    // Setup to send SASL mechanisms frame
-    pni_sasl_set_desired_state(transport, SASL_POSTED_MECHANISMS);
+    if (!pni_init_server_(transport)) return;
   }
 }
 
@@ -366,6 +446,9 @@ static ssize_t pn_output_write_sasl(pn_transport_t* 
transport, unsigned int laye
 
   pni_sasl_start_server_if_needed(transport);
 
+  if (implementation) {
+    implementation->prepare(transport);//allow impl to adjust sasl object on 
the right thread if needed
+  }
   pni_post_sasl_frame(transport);
 
   if (transport->available != 0 || !pni_sasl_is_final_output_state(sasl)) {
@@ -520,7 +603,7 @@ void pn_sasl_free(pn_transport_t *transport)
 
       // CYRUS_SASL
       if (sasl->impl_context) {
-          pni_sasl_impl_free(transport);
+          pni_sasl_impl_free_(transport);
       }
       pn_buffer_free(sasl->decoded_buffer);
       pn_buffer_free(sasl->encoded_buffer);
@@ -620,7 +703,7 @@ int pn_do_init(pn_transport_t *transport, uint8_t 
frame_type, uint16_t channel,
   if (err) return err;
   sasl->selected_mechanism = pn_strndup(mech.start, mech.size);
 
-  pni_process_init(transport, sasl->selected_mechanism, &recv);
+  pni_process_init_(transport, sasl->selected_mechanism, &recv);
 
   return 0;
 }
@@ -661,11 +744,9 @@ int pn_do_mechanisms(pn_transport_t *transport, uint8_t 
frame_type, uint16_t cha
     pn_string_setn(mechs, symbol.start, symbol.size);
   }
 
-  if (pni_init_client(transport) &&
+  if (!(pni_init_client_(transport) &&
       pn_string_size(mechs) &&
-      pni_process_mechanisms(transport, pn_string_get(mechs))) {
-    pni_sasl_set_desired_state(transport, SASL_POSTED_INIT);
-  } else {
+      pni_process_mechanisms_(transport, pn_string_get(mechs)))) {
     sasl->outcome = PN_SASL_PERM;
     pni_sasl_set_desired_state(transport, SASL_RECVED_OUTCOME_FAIL);
   }
@@ -681,7 +762,7 @@ int pn_do_challenge(pn_transport_t *transport, uint8_t 
frame_type, uint16_t chan
   int err = pn_data_scan(args, "D.[z]", &recv);
   if (err) return err;
 
-  pni_process_challenge(transport, &recv);
+  pni_process_challenge_(transport, &recv);
 
   return 0;
 }
@@ -693,7 +774,7 @@ int pn_do_response(pn_transport_t *transport, uint8_t 
frame_type, uint16_t chann
   int err = pn_data_scan(args, "D.[z]", &recv);
   if (err) return err;
 
-  pni_process_response(transport, &recv);
+  pni_process_response_(transport, &recv);
 
   return 0;
 }
@@ -711,7 +792,10 @@ int pn_do_outcome(pn_transport_t *transport, uint8_t 
frame_type, uint16_t channe
   transport->authenticated = authenticated;
   pni_sasl_set_desired_state(transport, authenticated ? 
SASL_RECVED_OUTCOME_SUCCEED : SASL_RECVED_OUTCOME_FAIL);
 
+  if (implementation) {
+    implementation->process_outcome(transport);
+  }
+
   return 0;
 }
 
-


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

Reply via email to