Skip to content

Conversation

@emelialei88
Copy link
Collaborator

@emelialei88 emelialei88 commented Jun 10, 2025

This PR apply plugin into authentication and reauthentication when we as a broker receives authentication requests from clients.

  • Added component rawclient to support integration test test_authn.py.
  • Added plugin bmqauthnbasic for testing. It uses "basic" as mechanism and creates an in-memory map for username and password.
  • Used plugin to authenticate and reauthenticate.
    • Authenticator is managed by TransportManager and referred to by InitialConnectionContext.
    • When sending response, we use the same encoding type as the one used by the client AuthenticationRequest.
    • Authentication with plugin is performed in a separate thread, and the channel is closed when there's a failure.
    • When AuthenticationContext is created during initial connection, create a reauthenticateCb to be called when a client session later receives an AuthenticationEvent.
    • Use AuthenticationContext::State to indicate the state of authentication. This is used as to make sure only one authentication is run for a given context, and when a channel closes, no more reauthentication timer will be scheduled.
  • Default authentication credential:
    • Credential = mechanism + identity
    • When we receive a ClientIdentity prior to any AuthenticateRequest, we use default credential to authenticate, unless it's explicitly set to Disallow.
    • Added AnonyPassAuthenticator (implementing mqbplug::Authenticator) and the corresponding factory and result under mqbauthn as default Authenticator.
  • A minor refactor to clarify the responsibility
    • Have TransportManager instead of InitialConnectionHandler own the Negotiator.
  • Added a timer to disconnect when the authenticated lifetime expires.
  • Added InitialConnectionContext::State to indicate the state of initial connection.

@emelialei88 emelialei88 requested a review from a team as a code owner June 10, 2025 18:45
@emelialei88 emelialei88 marked this pull request as draft June 10, 2025 18:45
@emelialei88 emelialei88 force-pushed the integration/authn-authz branch 2 times, most recently from d8e0447 to 0f8a365 Compare June 18, 2025 15:21
@emelialei88 emelialei88 force-pushed the authn/use-plugin branch 4 times, most recently from 057a7c2 to ec64999 Compare June 20, 2025 19:16
@emelialei88 emelialei88 force-pushed the integration/authn-authz branch 2 times, most recently from d74e1fe to 2d81dff Compare June 20, 2025 19:32
@emelialei88 emelialei88 force-pushed the authn/use-plugin branch 3 times, most recently from 85e7ca0 to 6441933 Compare June 23, 2025 15:58
@emelialei88 emelialei88 force-pushed the integration/authn-authz branch 3 times, most recently from a6885dd to c2820a5 Compare June 25, 2025 16:23
@emelialei88 emelialei88 force-pushed the integration/authn-authz branch from c2820a5 to 1217636 Compare July 10, 2025 21:46
@emelialei88 emelialei88 marked this pull request as ready for review July 15, 2025 15:18
@emelialei88 emelialei88 requested a review from pniedzielski July 15, 2025 15:18
Copy link
Collaborator

@pniedzielski pniedzielski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partial review

STOP_OBJ(d_configProvider_mp, "ConfigProvider");
STOP_OBJ(d_statController_mp, "StatController");
STOP_OBJ(d_authenticationController_mp, "AuthenticationController");
STOP_OBJ(d_statController_mp, "StatController");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the DESTROY_OBJ change below look important. Is this because we use stats in our auth controller?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet. This change is made since StatController starts first before AuthenticationController, so when stopping I wanted to have them in reverse order.

@emelialei88 emelialei88 force-pushed the authn/use-plugin branch 3 times, most recently from a873f88 to fbb6bec Compare July 21, 2025 21:53
@emelialei88 emelialei88 force-pushed the integration/authn-authz branch from 1217636 to 1128950 Compare July 25, 2025 17:54
@emelialei88 emelialei88 force-pushed the authn/use-plugin branch 4 times, most recently from 6f49b6b to da77f6c Compare October 8, 2025 16:19
@emelialei88 emelialei88 removed their assignment Oct 10, 2025
Copy link
Collaborator

@dorjesinpo dorjesinpo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to revisit the reason for shared_from, see my big comment
Few other comments.


int rc = rc_SUCCESS;
bsl::string error;
mqbnet::InitialConnectionEvent::Enum input;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mqbnet::InitialConnectionEvent::Enum input;
mqbnet::InitialConnectionEvent::Enum event = InitialConnectionEvent::e_ERROR;

And remove all input = InitialConnectionEvent::e_ERROR;

if (processRc != rc_SUCCESS) {
rc = (processRc * 10) + rc_PROCESS_AUTHENTICATION_FAILED;
error = processErrStream.str();
input = InitialConnectionEvent::e_ERROR;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
input = InitialConnectionEvent::e_ERROR;


// In the case of a default authentication, we do not need to send
// an AuthenticationResponse, we just need to continue the negotiation.
if (context->state() ==
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

safer way is to explicitly specify the e_DEFAULT_AUTHENTICATING case as an argument to Authenticator::handleAuthentication and not read the state which the FSM can potentially change.
Or, introduce Authenticator::handleDefaultAuthentication.
Or, make a decision on something other than the state, something immutable. For example, authenticationMsg.
Notice how InitialConnectionContext calls d_authenticator_p->anonymousCredential(), can it be done by the authenticator itself?

/// context.
/// It is set during the initial authentication, and is null for
/// reauthentication.
InitialConnectionContext* d_initialConnectionContext_p;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like we do not need it!

<< channel->peerUri() << "' [error: " << errorName
<< ", code: " << errorCode << "]";

bmqio::Status status(bmqio::StatusCategory::e_GENERIC_ERROR,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to use less generic error category (e_CANCELED?)

void InitialConnectionContext::readCallback(const bmqio::Status& status,
int* numNeeded,
bdlbb::Blob* blob)
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// executed by one of the *IO* threads

bmqu::MemOutStream errStream;
int rc = rc_SUCCESS;

rc = readBlob(errStream, &outPacket, &isFullBlob, status, numNeeded, blob);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor. why not check the status before calling readBlob?


bsl::shared_ptr<mqbnet::Session> session;

if (rc == 0 && d_state == State::e_NEGOTIATED) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if using enum rc_SUCCESS, let's use it everywhere

bsl::shared_ptr<InitialConnectionContext> self = shared_from_this();

bmqu::MemOutStream errStream(d_allocator_p);
int rc = rc_SUCCESS;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly already made suggestion to initialize rc with rc_ERROR.
Easier to explicitly set rc_SUCCESS than making sure we don't handle error without rc = rc_ERROR;

const bsl::variant<bsl::monostate,
bmqp_ctrlmsg::AuthenticationMessage,
bmqp_ctrlmsg::NegotiationMessage>& message)
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// executed by *ANY* thread

@dorjesinpo dorjesinpo assigned emelialei88 and unassigned dorjesinpo Oct 15, 2025
@emelialei88 emelialei88 force-pushed the authn/use-plugin branch 3 times, most recently from 71f8e49 to 05f71f1 Compare October 16, 2025 18:26
Signed-off-by: Emelia Lei <[email protected]>
@emelialei88 emelialei88 merged commit d49eb88 into bloomberg:integration/authn-authz Oct 17, 2025
38 of 39 checks passed
@emelialei88
Copy link
Collaborator Author

integration/authn-authz branch will be used as a temporary workspace and it will not be merged into main. Separate smaller PRs will be created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants