diff options
Diffstat (limited to 'cpp/src/qpid/broker/PreviewConnectionHandler.cpp')
-rw-r--r-- | cpp/src/qpid/broker/PreviewConnectionHandler.cpp | 198 |
1 files changed, 141 insertions, 57 deletions
diff --git a/cpp/src/qpid/broker/PreviewConnectionHandler.cpp b/cpp/src/qpid/broker/PreviewConnectionHandler.cpp index 48b8997545..3a19ef416d 100644 --- a/cpp/src/qpid/broker/PreviewConnectionHandler.cpp +++ b/cpp/src/qpid/broker/PreviewConnectionHandler.cpp @@ -69,11 +69,43 @@ void PreviewConnectionHandler::handle(framing::AMQFrame& frame) PreviewConnectionHandler::PreviewConnectionHandler(PreviewConnection& connection, bool isClient) : handler(new Handler(connection)) { FieldTable properties; - string mechanisms(PLAIN); + string mechanisms; string locales(en_US); if (isClient) { handler->serverMode = false; }else { +// +// TODO: The code below is the proper way to create a mechanisms list, +// but it cannot be done here because the sasl_conn has not been +// initialized. Unfortunately, sasl_conn cannot be initialize here +// because an exception thrown from this constructor will result in +// the Broker exiting, and dropping core. +// +//#if HAVE_SASL +// const char *list; +// unsigned int list_len; +// int count; +// int code = sasl_listmech(sasl_conn, NULL, +// "", " ", "", +// &list, &list_len, +// &count); +// +// if (SASL_OK != code) { +// QPID_LOG(info, "SASL: Mechanism listing failed: " +// << sasl_errdetail(sasl_conn)); +// +// // TODO: Change this to an exception signaling +// // server error, when one is available +// throw CommandInvalidException("Mechanism listing failed"); +// } else { +// // TODO: Figure out the proper way to specify multiple +// // mechanisms. Right now mechanisms are separated by +// // spaces. +// mechanisms = list; +// } +//#else + mechanisms = PLAIN; +//#endif handler->serverMode = true; handler->client.start(99, 0, properties, mechanisms, locales); } @@ -89,7 +121,7 @@ PreviewConnectionHandler::Handler::Handler(PreviewConnection& c) : PreviewConnectionHandler::Handler::~Handler() { -#if HAVE_LIBSASL2 +#if HAVE_SASL if (NULL != sasl_conn) { sasl_dispose(&sasl_conn); sasl_conn = NULL; @@ -97,71 +129,123 @@ PreviewConnectionHandler::Handler::~Handler() #endif } -void PreviewConnectionHandler::Handler::startOk(const framing::FieldTable& /*clientProperties*/, - const string& mechanism, - const string& response, const string& /*locale*/) +#if HAVE_SASL +void PreviewConnectionHandler::Handler::processAuthenticationStep(int code, const char *challenge, unsigned int challenge_len) { - //TODO: handle SASL mechanisms more cleverly - if (mechanism == PLAIN) { - QPID_LOG(info, "SASL Plain: Attempting authentication"); - if (response.size() > 0 && response[0] == (char) 0) { - string temp = response.substr(1); - string::size_type i = temp.find((char)0); - string uid = temp.substr(0, i); - string pwd = temp.substr(i + 1); + if (SASL_OK == code) { + const void *uid; -#if HAVE_SASL - if (connection.getBroker().getOptions().auth) { - int code = sasl_server_new(BROKER_SASL_NAME, - NULL, NULL, NULL, NULL, NULL, 0, - &sasl_conn); - - if (SASL_OK != code) { - QPID_LOG(info, "SASL Plain: Connection creation failed: " - << sasl_errdetail(sasl_conn)); - - // TODO: Change this to an exception signaling - // server error, when one is available - throw CommandInvalidException("Unable to perform authentication"); - } - - code = sasl_checkpass(sasl_conn, - uid.c_str(), uid.length(), - pwd.c_str(), pwd.length()); - if (SASL_OK == code) { - QPID_LOG(info, "SASL Plain: Authentication accepted for " << uid); - } else { - // See man sasl_errors(3) or sasl/sasl.h for possible errors - QPID_LOG(info, "SASL Plain: Authentication rejected for " - << uid << ": " - << sasl_errdetail(sasl_conn)); - - // TODO: Change this to an exception signaling - // authentication failure, when one is available - throw ConnectionForcedException("Authentication failed"); - } - } else { + code = sasl_getprop(sasl_conn, + SASL_USERNAME, + &uid); + if (SASL_OK != code) { + QPID_LOG(info, "SASL: Authentication succeeded, username unavailable"); + // TODO: Change this to an exception signaling + // authentication failure, when one is available + throw ConnectionForcedException("Authenticated username unavailable"); + } + + QPID_LOG(info, "SASL: Authentication succeeded for: " << (char *)uid); + + connection.setUserId((char *)uid); + + client.tune(framing::CHANNEL_MAX, + connection.getFrameMax(), + connection.getHeartbeat()); + } else if (SASL_CONTINUE == code) { + string challenge_str(challenge, challenge_len); + + QPID_LOG(debug, "SASL: sending challenge to client"); + + client.secure(challenge_str); + } else { + QPID_LOG(info, "SASL: Authentication failed: " + << sasl_errdetail(sasl_conn)); + + // TODO: Change to more specific exceptions, when they are + // available + switch (code) { + case SASL_NOMECH: + throw ConnectionForcedException("Unsupported mechanism"); + break; + case SASL_TRYAGAIN: + throw ConnectionForcedException("Transient failure, try again"); + break; + default: + throw ConnectionForcedException("Authentication failed"); + break; + } + } +} #endif - QPID_LOG(warning, - "SASL Plain Warning: No Authentication Performed for " - << uid); + +void PreviewConnectionHandler::Handler::startOk(const framing::FieldTable& /*clientProperties*/, #if HAVE_SASL - } + const string& mechanism, + const string& response, +#else + const string& /*mechanism*/, + const string& /*response*/, #endif + const string& /*locale*/) +{ +#if HAVE_SASL + if (connection.getBroker().getOptions().auth) { + int code = sasl_server_new(BROKER_SASL_NAME, + NULL, NULL, NULL, NULL, NULL, 0, + &sasl_conn); + + if (SASL_OK != code) { + QPID_LOG(info, "SASL: Connection creation failed: " + << sasl_errdetail(sasl_conn)); - connection.setUserId(uid); + // TODO: Change this to an exception signaling + // server error, when one is available + throw CommandInvalidException("Unable to perform authentication"); } + + const char *challenge; + unsigned int challenge_len; + + QPID_LOG(info, "SASL: Starting authentication with mechanism: " << mechanism); + code = sasl_server_start(sasl_conn, + mechanism.c_str(), + response.c_str(), response.length(), + &challenge, &challenge_len); + + processAuthenticationStep(code, challenge, challenge_len); } else { - // The 0-10 spec states that if the client requests a - // mechanism not proposed by the server the server MUST - // close the connection. Assumption here is if we proposed - // a mechanism we'd have a case for it above. - throw NotImplementedException("Unsupported authentication mechanism"); - } - client.tune(framing::CHANNEL_MAX, connection.getFrameMax(), connection.getHeartbeat()); +#endif + QPID_LOG(warning, "SASL: No Authentication Performed"); + + // TODO: Figure out what should actually be set in this case + connection.setUserId("anonymous"); + + client.tune(framing::CHANNEL_MAX, + connection.getFrameMax(), + connection.getHeartbeat()); +#if HAVE_SASL + } +#endif } -void PreviewConnectionHandler::Handler::secureOk(const string& /*response*/){} +void PreviewConnectionHandler::Handler::secureOk(const string& +#if HAVE_SASL + response +#endif + ) { +#if HAVE_SASL + int code; + const char *challenge; + unsigned int challenge_len; + + code = sasl_server_step(sasl_conn, + response.c_str(), response.length(), + &challenge, &challenge_len); + + processAuthenticationStep(code, challenge, challenge_len); +#endif +} void PreviewConnectionHandler::Handler::tuneOk(uint16_t /*channelmax*/, uint32_t framemax, uint16_t heartbeat) |