You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by tr...@apache.org on 2014/08/06 16:24:26 UTC
svn commit: r1616245 - in /qpid/proton/trunk:
proton-c/bindings/python/proton.py proton-c/include/proton/cproton.i
proton-c/include/proton/sasl.h proton-c/src/sasl/sasl.c
tests/python/proton_tests/sasl.py
Author: tross
Date: Wed Aug 6 14:24:25 2014
New Revision: 1616245
URL: http://svn.apache.org/r1616245
Log:
PROTON-485 - Make SASL server tolerant of clients that skip SASL
Modified:
qpid/proton/trunk/proton-c/bindings/python/proton.py
qpid/proton/trunk/proton-c/include/proton/cproton.i
qpid/proton/trunk/proton-c/include/proton/sasl.h
qpid/proton/trunk/proton-c/src/sasl/sasl.c
qpid/proton/trunk/tests/python/proton_tests/sasl.py
Modified: qpid/proton/trunk/proton-c/bindings/python/proton.py
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/bindings/python/proton.py?rev=1616245&r1=1616244&r2=1616245&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/bindings/python/proton.py (original)
+++ qpid/proton/trunk/proton-c/bindings/python/proton.py Wed Aug 6 14:24:25 2014
@@ -3131,6 +3131,7 @@ class SASL(object):
OK = PN_SASL_OK
AUTH = PN_SASL_AUTH
+ SKIPPED = PN_SASL_SKIPPED
def __new__(cls, transport):
"""Enforce a singleton SASL object per Transport"""
@@ -3156,6 +3157,9 @@ class SASL(object):
def server(self):
pn_sasl_server(self._sasl)
+ def allow_skip(self, allow):
+ pn_sasl_allow_skip(self._sasl, allow)
+
def plain(self, user, password):
pn_sasl_plain(self._sasl, user, password)
Modified: qpid/proton/trunk/proton-c/include/proton/cproton.i
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/include/proton/cproton.i?rev=1616245&r1=1616244&r2=1616245&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/include/proton/cproton.i (original)
+++ qpid/proton/trunk/proton-c/include/proton/cproton.i Wed Aug 6 14:24:25 2014
@@ -77,7 +77,7 @@ typedef long long int int64_t;
%aggregate_check(int, check_sasl_outcome,
PN_SASL_NONE, PN_SASL_OK, PN_SASL_AUTH,
- PN_SASL_SYS, PN_SASL_PERM, PN_SASL_TEMP);
+ PN_SASL_SYS, PN_SASL_PERM, PN_SASL_TEMP, PN_SASL_SKIPPED);
%aggregate_check(int, check_sasl_state,
PN_SASL_CONF, PN_SASL_IDLE, PN_SASL_STEP,
@@ -999,6 +999,12 @@ typedef long long int int64_t;
sasl != NULL;
}
+%contract pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
+{
+ require:
+ sasl != NULL;
+}
+
%contract pn_sasl_plain(pn_sasl_t *sasl, const char *username, const char *password)
{
require:
Modified: qpid/proton/trunk/proton-c/include/proton/sasl.h
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/include/proton/sasl.h?rev=1616245&r1=1616244&r2=1616245&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/include/proton/sasl.h (original)
+++ qpid/proton/trunk/proton-c/include/proton/sasl.h Wed Aug 6 14:24:25 2014
@@ -54,7 +54,8 @@ typedef enum {
PN_SASL_AUTH=1, /** failed due to bad credentials */
PN_SASL_SYS=2, /** failed due to a system error */
PN_SASL_PERM=3, /** failed due to unrecoverable error */
- PN_SASL_TEMP=4 /** failed due to transient error */
+ PN_SASL_TEMP=4, /** failed due to transient error */
+ PN_SASL_SKIPPED=5 /** the peer didn't perform the sasl exchange */
} pn_sasl_outcome_t;
/** The state of the SASL negotiation process */
@@ -113,6 +114,18 @@ PN_EXTERN void pn_sasl_client(pn_sasl_t
*/
PN_EXTERN void pn_sasl_server(pn_sasl_t *sasl);
+/** Configure a SASL server layer to permit the client to skip the SASL exchange.
+ *
+ * If the peer client skips the SASL exchange (i.e. goes right to the AMQP header)
+ * this server layer will succeed and result in the outcome of PN_SASL_SKIPPED.
+ * The default behavior is to fail and close the connection if the client skips
+ * SASL.
+ *
+ * @param[in] sasl the SASL layer to configure
+ * @param[in] allow true -> allow skip; false -> forbid skip
+ */
+ PN_EXTERN void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow);
+
/** Configure the SASL layer to use the "PLAIN" mechanism.
*
* A utility function to configure a simple client SASL layer using
Modified: qpid/proton/trunk/proton-c/src/sasl/sasl.c
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/proton-c/src/sasl/sasl.c?rev=1616245&r1=1616244&r2=1616245&view=diff
==============================================================================
--- qpid/proton/trunk/proton-c/src/sasl/sasl.c (original)
+++ qpid/proton/trunk/proton-c/src/sasl/sasl.c Wed Aug 6 14:24:25 2014
@@ -42,10 +42,10 @@ struct pn_sasl_t {
char *remote_mechanisms;
pn_buffer_t *send_data;
pn_buffer_t *recv_data;
- size_t header_count;
pn_sasl_outcome_t outcome;
bool client;
bool configured;
+ bool allow_skip;
bool sent_init;
bool rcvd_init;
bool sent_done;
@@ -71,6 +71,7 @@ pn_sasl_t *pn_sasl(pn_transport_t *trans
sasl->send_data = pn_buffer(16);
sasl->recv_data = pn_buffer(16);
sasl->outcome = PN_SASL_NONE;
+ sasl->allow_skip = false;
sasl->sent_init = false;
sasl->rcvd_init = false;
sasl->sent_done = false;
@@ -83,8 +84,6 @@ pn_sasl_t *pn_sasl(pn_transport_t *trans
sasl->io_layer->process_input = pn_input_read_sasl_header;
sasl->io_layer->process_output = pn_output_write_sasl_header;
sasl->io_layer->process_tick = pn_io_layer_tick_passthru;
-
- sasl->header_count = 0;
}
return transport->sasl;
@@ -173,6 +172,12 @@ void pn_sasl_server(pn_sasl_t *sasl)
}
}
+void pn_sasl_allow_skip(pn_sasl_t *sasl, bool allow)
+{
+ if (sasl)
+ sasl->allow_skip = allow;
+}
+
void pn_sasl_plain(pn_sasl_t *sasl, const char *username, const char *password)
{
if (!sasl) return;
@@ -396,28 +401,44 @@ int pn_do_outcome(pn_dispatcher_t *disp)
}
#define SASL_HEADER ("AMQP\x03\x01\x00\x00")
+#define AMQP_HEADER ("AMQP\x00\x01\x00\x00")
#define SASL_HEADER_LEN 8
static ssize_t pn_input_read_sasl_header(pn_io_layer_t *io_layer, const char *bytes, size_t available)
{
pn_sasl_t *sasl = (pn_sasl_t *)io_layer->context;
- const char *point = SASL_HEADER + sasl->header_count;
- int delta = pn_min(available, SASL_HEADER_LEN - sasl->header_count);
- if (!available || memcmp(bytes, point, delta)) {
- char quoted[1024];
- pn_quote_data(quoted, 1024, bytes, available);
- pn_do_error(sasl->transport, "amqp:connection:framing-error",
- "%s header mismatch: '%s'", "SASL", quoted);
- return PN_EOS;
- } else {
- sasl->header_count += delta;
- if (sasl->header_count == SASL_HEADER_LEN) {
- sasl->io_layer->process_input = pn_input_read_sasl;
- if (sasl->disp->trace & PN_TRACE_FRM)
- pn_transport_logf(sasl->transport, " <- %s", "SASL");
+ if (available > 0) {
+ if (available < SASL_HEADER_LEN) {
+ if (memcmp(bytes, SASL_HEADER, available) == 0 ||
+ memcmp(bytes, AMQP_HEADER, available) == 0)
+ return 0;
+ } else {
+ if (memcmp(bytes, SASL_HEADER, SASL_HEADER_LEN) == 0) {
+ sasl->io_layer->process_input = pn_input_read_sasl;
+ if (sasl->disp->trace & PN_TRACE_FRM)
+ pn_transport_logf(sasl->transport, " <- %s", "SASL");
+ return SASL_HEADER_LEN;
+ }
+ if (memcmp(bytes, AMQP_HEADER, SASL_HEADER_LEN) == 0) {
+ if (sasl->allow_skip) {
+ sasl->outcome = PN_SASL_SKIPPED;
+ sasl->io_layer->process_input = pn_io_layer_input_passthru;
+ sasl->io_layer->process_output = pn_io_layer_output_passthru;
+ pn_io_layer_t *io_next = sasl->io_layer->next;
+ return io_next->process_input( io_next, bytes, available );
+ } else {
+ pn_do_error(sasl->transport, "amqp:connection:policy-error",
+ "Client skipped SASL exchange - forbidden");
+ return PN_EOS;
+ }
+ }
}
- return delta;
}
+ char quoted[1024];
+ pn_quote_data(quoted, 1024, bytes, available);
+ pn_do_error(sasl->transport, "amqp:connection:framing-error",
+ "%s header mismatch: '%s'", "SASL", quoted);
+ return PN_EOS;
}
static ssize_t pn_input_read_sasl(pn_io_layer_t *io_layer, const char *bytes, size_t available)
Modified: qpid/proton/trunk/tests/python/proton_tests/sasl.py
URL: http://svn.apache.org/viewvc/qpid/proton/trunk/tests/python/proton_tests/sasl.py?rev=1616245&r1=1616244&r2=1616245&view=diff
==============================================================================
--- qpid/proton/trunk/tests/python/proton_tests/sasl.py (original)
+++ qpid/proton/trunk/tests/python/proton_tests/sasl.py Wed Aug 6 14:24:25 2014
@@ -191,3 +191,13 @@ class SaslTest(Test):
sasl1 = transport.sasl()
sasl2 = SASL(transport)
assert sasl1 is sasl2
+
+ def testSaslSkipped(self):
+ """Verify that the server (with SASL) correctly handles a client without SASL"""
+ self.t1 = Transport()
+ self.s2.mechanisms("ANONYMOUS")
+ self.s2.server()
+ self.s2.allow_skip(True)
+ self.pump()
+ assert self.s2.outcome == SASL.SKIPPED
+
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org