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
dorjesinpo and others added 2 commits September 25, 2025 14:41
Signed-off-by: dorjesinpo <129227380+dorjesinpo@users.noreply.github.com>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
@emelialei88 emelialei88 force-pushed the authn/use-plugin branch 3 times, most recently from 348789c to 5d15c0d Compare September 25, 2025 21:23
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
@emelialei88 emelialei88 assigned 678098 and dorjesinpo and unassigned pniedzielski Sep 30, 2025
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Copy link
Collaborator

@678098 678098 left a comment

Choose a reason for hiding this comment

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

Could you also rebase the branch to the latest main to allow Solaris build?

Copy link
Collaborator

@678098 678098 left a comment

Choose a reason for hiding this comment

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

Could you also rebase the branch to the latest main to allow Solaris build?

@678098 678098 assigned emelialei88 and unassigned 678098 Oct 1, 2025
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Signed-off-by: Emelia Lei <wlei29@bloomberg.net>
Copy link
Collaborator Author

@emelialei88 emelialei88 left a comment

Choose a reason for hiding this comment

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

Addressed the review from @678098 and responded to some questions.

int rc = decodeInitialConnectionMessage(errorDescription, &message, blob);

if (rc != rc_SUCCESS) {
return (rc * 10) + rc_INVALID_INITIALCONNECTION_MESSAGE; // RETURN
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 sure what you mean. Isn't errorDescription populated from decodeInitialConnectionMessage?

{
// PRECONDITIONS
BSLS_ASSERT_OPT(!d_isStarted &&
"start() can only be called once on this object");
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I thought that's what I'm doing here?


/// Return the anonymous credential used for authentication.
/// If no anonymous credential is set, return an empty optional.
const bsl::optional<mqbcfg::Credential>& anonymousCredential();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

optional doesn't help to bypass including this file. mqbplug_pluginmanager does include it tho if you think we can just use the one from mqbplug_pluginmanager.

bdlmt::EventScheduler* d_scheduler;

/// Allocator to use.
bslma::Allocator* d_allocator_p;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't mind reordering but kind of want to keep d_allocator_p at the end cuz it helps to eliminate one extra parameter when calling allocate_shared.

namespace mqbnet {

namespace {
BALL_LOG_SET_NAMESPACE_CATEGORY("MQBNET.AUTHENTICATIONCONTEXT");
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah this was a misused but I'm sure there's no error or crash.

Comment on lines +96 to +100
const mqbcfg::AuthenticatorPluginConfig* d_authenticatorConfig_p;

bool d_isStarted;

bslma::Allocator* d_allocator_p;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Maybe not a big deal but putting d_allocator_p to the front would cause one extra variable provided toallocate_shared.

{
bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex); // LOCKED

if (d_state == State::e_CLOSED) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The point of using a single mutex was bcz it's simpler to reason about the potential race condition between scheduling a reauthn event and closing a channel, making sure changing the state to e_CLOSED and cancelEventAndWait happen at the same time. We could use an atomic but there's a few places I still have to hold a mutex while accessing it. So I'm leaning towards just use one mutex unless you have a strong opinion against this idea. Thanks!

{
bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);

return d_state == state;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See the comments above.

Copy link
Collaborator

@678098 678098 left a comment

Choose a reason for hiding this comment

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

More comments
I can test the build on Solaris when the branch is rebased from the latest main

class Authenticator : public mqbnet::Authenticator {
private:
// CLASS-SCOPE CATEGORY
BALL_LOG_SET_CLASS_CATEGORY("MQBNET.AUTHENTICATIONCONTEXT");
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
BALL_LOG_SET_CLASS_CATEGORY("MQBNET.AUTHENTICATIONCONTEXT");
BALL_LOG_SET_CLASS_CATEGORY("MQBA.AUTHENTICATOR");

bdlmt::EventScheduler* d_scheduler;

/// Allocator to use.
bslma::Allocator* d_allocator_p;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you mean the fact that we omit the last allocator arg when calling allocate_shared? allocate_shared looks at class traits and if there is allocator trait it always passes an allocator as the last arg to constructor automatically.
The important thing is to keep allocator arg the last in the constructor, but it can be placed in the first place in the class fields.

{
// PRECONDITIONS
BSLS_ASSERT_OPT(!d_isStarted &&
"start() can only be called once on this object");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it should be symmetrical, to make the codebase simpler and predictable.
Might either gracefully handle multiple start/stop, or assert in both cases.
Probably it's better to handle without crash.


public:
// TRAITS
BSLMF_NESTED_TRAIT_DECLARATION(Authenticator, bslma::UsesBslmaAllocator)
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
BSLMF_NESTED_TRAIT_DECLARATION(Authenticator, bslma::UsesBslmaAllocator)
BSLMF_NESTED_TRAIT_DECLARATION(AnonPassAuthenticator, bslma::UsesBslmaAllocator)

Comment on lines +96 to +100
const mqbcfg::AuthenticatorPluginConfig* d_authenticatorConfig_p;

bool d_isStarted;

bslma::Allocator* d_allocator_p;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The problem might be with missing/incorrect allocated nested trait that is used by allocate_shared, if it is present and correct, there should be no last allocator arg in allocate_shared


public:
// TRAITS
BSLMF_NESTED_TRAIT_DECLARATION(AuthenticationContext,
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
BSLMF_NESTED_TRAIT_DECLARATION(AuthenticationContext,
BSLMF_NESTED_TRAIT_DECLARATION(InitialConnectionContext,


public:
// TRAITS
BSLMF_NESTED_TRAIT_DECLARATION(PassAuthenticationResult,
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
BSLMF_NESTED_TRAIT_DECLARATION(PassAuthenticationResult,
BSLMF_NESTED_TRAIT_DECLARATION(PassAuthenticator,

If the provided class name doesn't match the current class name the trait will not work


public:
// TRAITS
BSLMF_NESTED_TRAIT_DECLARATION(FailAuthenticationResult,
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
BSLMF_NESTED_TRAIT_DECLARATION(FailAuthenticationResult,
BSLMF_NESTED_TRAIT_DECLARATION(FailAuthenticator,


public:
// TRAITS
BSLMF_NESTED_TRAIT_DECLARATION(BasicAuthenticationResult,
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
BSLMF_NESTED_TRAIT_DECLARATION(BasicAuthenticationResult,
BSLMF_NESTED_TRAIT_DECLARATION(BasicAuthenticator,

Comment on lines +24 to +25
// BMQ

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
// BMQ

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