4545#include < ball_log.h>
4646#include < bdlf_bind.h>
4747#include < bdlma_sequentialallocator.h>
48+ #include < bdlmt_eventscheduler.h>
4849#include < bdlmt_threadpool.h>
4950#include < bsl_memory.h>
5051#include < bsl_ostream.h>
52+ #include < bsl_string_view.h>
5153#include < bsls_nullptr.h>
5254#include < bsls_timeinterval.h>
5355
@@ -188,7 +190,8 @@ void Authenticator::authenticate(
188190 rc_AUTHENTICATION_STATE_INCORRECT = -1 ,
189191 rc_AUTHENTICATION_FAILED = -2 ,
190192 rc_SEND_AUTHENTICATION_RESPONSE_FAILED = -3 ,
191- rc_CONTINUE_READ_FAILED = -4
193+ rc_CONTINUE_READ_FAILED = -4 ,
194+ rc_AUTHENTICATION_TIMEOUT = -5
192195 };
193196
194197 const AuthenticationContextSp& authenticationContext =
@@ -247,6 +250,28 @@ void Authenticator::authenticate(
247250 bsl::shared_ptr<mqbnet::Session>());
248251 return ; // RETURN
249252 }
253+
254+ // Schedule authentication timeout
255+ if (result->lifetimeMs ().has_value ()) {
256+ bslmt::LockGuard<bslmt::Mutex> guard (
257+ &authenticationContext->timeoutHandleMutex ()); // MUTEX LOCKED
258+
259+ if (authenticationContext->timeoutHandle ()) {
260+ BALL_LOG_INFO << " timeout handle already has value" ;
261+ }
262+
263+ d_scheduler.scheduleEvent (
264+ &authenticationContext->timeoutHandle (),
265+ bsls::TimeInterval (bmqsys::Time::nowMonotonicClock ())
266+ .addMilliseconds (result->lifetimeMs ().value ()),
267+ bdlf::BindUtil::bind (
268+ &Authenticator::reauthenticateErrorOrTimeout,
269+ this , // authenticator
270+ rc_AUTHENTICATION_TIMEOUT, // errorCode
271+ " authenticationTimeout" , // errorName
272+ channel // channel
273+ ));
274+ }
250275 }
251276
252277 // This is when we authenticate with default credentials
@@ -328,7 +353,16 @@ void Authenticator::reauthenticate(
328353{
329354 // PRECONDITIONS
330355 BSLS_ASSERT (context);
331- BSLS_ASSERT (context->initialConnectionContext ());
356+
357+ enum RcEnum {
358+ // Value for the various RC error categories
359+ rc_SUCCESS = 0 ,
360+ rc_AUTHENTICATION_STATE_INCORRECT = -1 ,
361+ rc_AUTHENTICATION_FAILED = -2 ,
362+ rc_SEND_AUTHENTICATION_RESPONSE_FAILED = -3 ,
363+ rc_CONTINUE_READ_FAILED = -4 ,
364+ rc_AUTHENTICATION_TIMEOUT = -5
365+ };
332366
333367 const bmqp_ctrlmsg::AuthenticateRequest& authenticateRequest =
334368 context->authenticationMessage ().authenticateRequest ();
@@ -352,6 +386,7 @@ void Authenticator::reauthenticate(
352386 &result,
353387 authenticateRequest.mechanism (),
354388 authenticationData);
389+
355390 if (rc != 0 ) {
356391 BALL_LOG_ERROR << " Reauthentication failed for connection '"
357392 << channel->peerUri () << " ' with mechanism '"
@@ -362,20 +397,6 @@ void Authenticator::reauthenticate(
362397 response.status ().code () = rc;
363398 response.status ().category () = bmqp_ctrlmsg::StatusCategory::E_REFUSED;
364399 response.status ().message () = authenticationErrorStream.str ();
365-
366- // send the error response back to the client before calling the
367- // completion callback
368- bmqu::MemOutStream sendResponseErrorStream;
369- sendAuthenticationMessage (sendResponseErrorStream,
370- authenticationResponse,
371- channel,
372- context->authenticationEncodingType ());
373-
374- bmqio::Status status (bmqio::StatusCategory::e_GENERIC_ERROR,
375- " reauthenticationError" ,
376- rc,
377- d_allocator_p);
378- channel->close (status);
379400 }
380401 else {
381402 response.status ().code () = 0 ;
@@ -390,29 +411,73 @@ void Authenticator::reauthenticate(
390411 BALL_LOG_ERROR << " Failed to set (re)authentication state for '"
391412 << channel->peerUri ()
392413 << " ' to 'e_AUTHENTICATED' from 'e_AUTHENTICATING'" ;
393- bmqio::Status status (bmqio::StatusCategory::e_GENERIC_ERROR,
394- " reauthenticationError" ,
395- rc,
396- d_allocator_p);
397- channel->close (status);
414+ reauthenticateErrorOrTimeout ((rc * 10 ) +
415+ rc_AUTHENTICATION_STATE_INCORRECT,
416+ " reauthenticationError" ,
417+ channel);
398418 return ; // RETURN
399419 }
400420
401- // send the success response back to the client
402- bmqu::MemOutStream sendResponseErrorStream;
403- rc = sendAuthenticationMessage (sendResponseErrorStream,
404- authenticationResponse,
405- channel,
406- context->authenticationEncodingType ());
407-
408- if (rc != 0 ) {
409- bmqio::Status status (bmqio::StatusCategory::e_GENERIC_ERROR,
410- " reauthenticationError" ,
411- rc,
412- d_allocator_p);
413- channel->close (status);
421+ // Schedule authentication timeout
422+ if (result->lifetimeMs ().has_value ()) {
423+ bslmt::LockGuard<bslmt::Mutex> guard (
424+ &context->timeoutHandleMutex ()); // MUTEX LOCKED
425+
426+ if (context->timeoutHandle ()) {
427+ d_scheduler.cancelEvent (&context->timeoutHandle ());
428+ }
429+
430+ d_scheduler.scheduleEvent (
431+ &context->timeoutHandle (),
432+ bsls::TimeInterval (bmqsys::Time::nowMonotonicClock () +
433+ result->lifetimeMs ().value ()),
434+ bdlf::BindUtil::bind (
435+ &Authenticator::reauthenticateErrorOrTimeout,
436+ this , // authenticator
437+ rc_AUTHENTICATION_TIMEOUT, // errorCode
438+ " authenticationTimeout" , // errorName
439+ channel // channel
440+ ));
414441 }
415442 }
443+
444+ // Send authentication response back to the client
445+ bmqu::MemOutStream sendResponseErrorStream;
446+ rc = sendAuthenticationMessage (sendResponseErrorStream,
447+ authenticationResponse,
448+ channel,
449+ context->authenticationEncodingType ());
450+ if (response.status ().category () !=
451+ bmqp_ctrlmsg::StatusCategory::E_SUCCESS) {
452+ reauthenticateErrorOrTimeout (rc_AUTHENTICATION_FAILED,
453+ " reauthenticationError" ,
454+ channel);
455+ }
456+ else if (rc != 0 ) {
457+ BALL_LOG_ERROR << sendResponseErrorStream.str ();
458+ reauthenticateErrorOrTimeout (
459+ (rc * 10 ) + rc_SEND_AUTHENTICATION_RESPONSE_FAILED,
460+ " reauthenticationError" ,
461+ channel);
462+ }
463+
464+ return ;
465+ }
466+
467+ void Authenticator::reauthenticateErrorOrTimeout (
468+ int errorCode,
469+ bsl::string_view errorName,
470+ const bsl::shared_ptr<bmqio::Channel>& channel)
471+ {
472+ BALL_LOG_ERROR << " Reauthentication error or timeout for '"
473+ << channel->peerUri () << " ' [error: " << errorName
474+ << " , code: " << errorCode << " ]" ;
475+
476+ bmqio::Status status (bmqio::StatusCategory::e_GENERIC_ERROR,
477+ errorName,
478+ errorCode,
479+ d_allocator_p);
480+ channel->close (status);
416481}
417482
418483// CREATORS
@@ -426,6 +491,7 @@ Authenticator::Authenticator(
426491 100 , // max threads
427492 bsls::TimeInterval (120 ).totalMilliseconds(), // idle time
428493 allocator)
494+ , d_scheduler(bsls::SystemClockType::e_MONOTONIC, allocator)
429495, d_blobSpPool_p(blobSpPool)
430496, d_allocator_p(allocator)
431497{
@@ -447,11 +513,19 @@ int Authenticator::start(bsl::ostream& errorDescription)
447513 return rc; // RETURN
448514 }
449515
516+ rc = d_scheduler.start ();
517+ if (rc != 0 ) {
518+ errorDescription << " Failed to start event scheduler for Authenticator"
519+ << " [rc: " << rc << " ]" ;
520+ return rc; // RETURN
521+ }
522+
450523 return 0 ;
451524}
452525
453526void Authenticator::stop ()
454527{
528+ d_scheduler.stop ();
455529 d_threadPool.stop ();
456530}
457531
@@ -462,30 +536,46 @@ int Authenticator::handleAuthentication(
462536{
463537 enum RcEnum {
464538 // Value for the various RC error categories
465- rc_SUCCESS = 0 ,
466- rc_ERROR = -1 ,
539+ rc_SUCCESS = 0 ,
540+ rc_DUPLICATE_AUTHENTICATION = -1 ,
541+ rc_HANDLE_MESSAGE_FAIL = -2 ,
542+ rc_INVALID_MESSAGE = -3 ,
467543 };
468544
469- bmqu::MemOutStream errStream;
470- int rc = rc_SUCCESS;
545+ int rc = rc_SUCCESS;
546+
547+ if (context->authenticationContext ()) {
548+ errorDescription
549+ << " Received another authentication message while waiting "
550+ " for negotiation message" ;
551+ return rc_DUPLICATE_AUTHENTICATION;
552+ }
471553
472554 switch (authenticationMsg.selectionId ()) {
473555 case bmqp_ctrlmsg::AuthenticationMessage::
474556 SELECTION_ID_AUTHENTICATE_REQUEST: {
475- rc = onAuthenticationRequest (errStream, authenticationMsg, context);
557+ rc = onAuthenticationRequest (errorDescription,
558+ authenticationMsg,
559+ context);
476560 } break ; // BREAK
477561 case bmqp_ctrlmsg::AuthenticationMessage::
478562 SELECTION_ID_AUTHENTICATE_RESPONSE: {
479- rc = onAuthenticationResponse (errStream, authenticationMsg, context);
563+ rc = onAuthenticationResponse (errorDescription,
564+ authenticationMsg,
565+ context);
480566 } break ; // BREAK
481567 default : {
482568 errorDescription
483569 << " Invalid authentication message received (unknown type): "
484570 << authenticationMsg;
485- return rc_ERROR ; // RETURN
571+ return rc_INVALID_MESSAGE ; // RETURN
486572 }
487573 }
488574
575+ if (rc != rc_SUCCESS) {
576+ rc = (rc * 10 ) + rc_HANDLE_MESSAGE_FAIL;
577+ }
578+
489579 return rc;
490580}
491581
0 commit comments