Skip to content

Commit 23f32d0

Browse files
committed
use plugin to authenticate
Signed-off-by: Emelia Lei <[email protected]>
1 parent a048da9 commit 23f32d0

19 files changed

+418
-86
lines changed

src/groups/bmq/bmqp/bmqp_event.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ class Event {
161161
/// returns true.
162162
Event clone(bslma::Allocator* allocator) const;
163163

164+
/// Return the encoding type of this Authentication event. The
165+
/// behavior is undefined unless `isAuthenticationEvent()` returns true.
166+
EncodingType::Enum authenticationEventEncodingType() const;
167+
164168
/// Return the type of this event. The behavior is undefined unless
165169
/// `isValid()` returns true.
166170
EventType::Enum type() const;
@@ -336,6 +340,10 @@ int Event::loadSchemaEvent(TYPE* message) const
336340
if (d_header->type() == EventType::e_CONTROL) {
337341
encodingType = EventHeaderUtil::controlEventEncodingType(*d_header);
338342
}
343+
else if (d_header->type() == EventType::e_AUTHENTICATION) {
344+
encodingType = EventHeaderUtil::authenticationEventEncodingType(
345+
*d_header);
346+
}
339347

340348
bmqu::MemOutStream os;
341349
int rc = ProtocolUtil::decodeMessage(os,
@@ -428,6 +436,14 @@ inline Event Event::clone(bslma::Allocator* allocator) const
428436
return Event(d_blob_p, allocator, true /* clone == true */);
429437
}
430438

439+
inline EncodingType::Enum Event::authenticationEventEncodingType() const
440+
{
441+
// PRECONDITIONS
442+
BSLS_ASSERT_SAFE(isAuthenticationEvent());
443+
444+
return EventHeaderUtil::authenticationEventEncodingType(*d_header);
445+
}
446+
431447
inline EventType::Enum Event::type() const
432448
{
433449
// PRECONDITIONS

src/groups/bmq/bmqp/bmqp_protocol.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,10 +928,20 @@ struct EventHeaderUtil {
928928
static void setControlEventEncodingType(EventHeader* eventHeader,
929929
EncodingType::Enum type);
930930

931+
/// Set the appropriate bits in the specified `eventHeader` to represent
932+
/// the specified encoding `type` for an authentication event.
933+
static void setAuthenticationEventEncodingType(EventHeader* eventHeader,
934+
EncodingType::Enum type);
935+
931936
/// Return the encoding type for a control event represented by the
932937
/// appropriate bits in the specified `eventHeader`.
933938
static EncodingType::Enum
934939
controlEventEncodingType(const EventHeader& eventHeader);
940+
941+
/// Return the encoding type for a authentication event represented by the
942+
/// appropriate bits in the specified `eventHeader`.
943+
static EncodingType::Enum
944+
authenticationEventEncodingType(const EventHeader& eventHeader);
935945
};
936946

937947
// ===================
@@ -3857,6 +3867,26 @@ EventHeaderUtil::setControlEventEncodingType(EventHeader* eventHeader,
38573867
eventHeader->setTypeSpecific(typeSpecific);
38583868
}
38593869

3870+
inline void
3871+
EventHeaderUtil::setAuthenticationEventEncodingType(EventHeader* eventHeader,
3872+
EncodingType::Enum type)
3873+
{
3874+
// PRECONDITIONS
3875+
BSLS_ASSERT_SAFE(eventHeader->type() == EventType::e_AUTHENTICATION);
3876+
BSLS_ASSERT_SAFE(type != EncodingType::e_UNKNOWN);
3877+
3878+
unsigned char typeSpecific = eventHeader->typeSpecific();
3879+
3880+
// Reset the bits for encoding type
3881+
typeSpecific &= static_cast<unsigned char>(~k_CONTROL_EVENT_ENCODING_MASK);
3882+
3883+
// Set those bits to represent 'type'
3884+
typeSpecific |= static_cast<unsigned char>(
3885+
type << k_CONTROL_EVENT_ENCODING_START_IDX);
3886+
3887+
eventHeader->setTypeSpecific(typeSpecific);
3888+
}
3889+
38603890
inline EncodingType::Enum
38613891
EventHeaderUtil::controlEventEncodingType(const EventHeader& eventHeader)
38623892
{
@@ -3869,6 +3899,18 @@ EventHeaderUtil::controlEventEncodingType(const EventHeader& eventHeader)
38693899
return static_cast<EncodingType::Enum>(encodingType);
38703900
}
38713901

3902+
inline EncodingType::Enum EventHeaderUtil::authenticationEventEncodingType(
3903+
const EventHeader& eventHeader)
3904+
{
3905+
// PRECONDITIONS
3906+
BSLS_ASSERT_SAFE(eventHeader.type() == EventType::e_AUTHENTICATION);
3907+
3908+
const unsigned char typeSpecific = eventHeader.typeSpecific();
3909+
const int encodingType = (typeSpecific & k_CONTROL_EVENT_ENCODING_MASK) >>
3910+
k_CONTROL_EVENT_ENCODING_START_IDX;
3911+
return static_cast<EncodingType::Enum>(encodingType);
3912+
}
3913+
38723914
// -------------------
38733915
// struct OptionHeader
38743916
// -------------------

src/groups/bmq/bmqp/bmqp_schemaeventbuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ int SchemaEventBuilder::setMessage(const TYPE& message, EventType::Enum type)
250250
EventHeaderUtil::setControlEventEncodingType(eventHeader,
251251
d_encodingType);
252252
}
253+
else if (type == EventType::e_AUTHENTICATION) {
254+
EventHeaderUtil::setAuthenticationEventEncodingType(eventHeader,
255+
d_encodingType);
256+
}
253257

254258
// Append appropriate encoding of 'message' to the blob
255259
int rc = ProtocolUtil::encodeMessage(d_errorStream,

src/groups/mqb/mqba/mqba_application.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,9 @@ int Application::start(bsl::ostream& errorDescription)
332332

333333
// Start the transport manager
334334
bslma::ManagedPtr<mqbnet::Authenticator> authenticatorMp(
335-
new (*d_allocator_p)
336-
Authenticator(&d_blobSpPool, d_allocators.get("Authenticator")),
335+
new (*d_allocator_p) Authenticator(d_authenticationController_mp.get(),
336+
&d_blobSpPool,
337+
d_allocators.get("Authenticator")),
337338
d_allocator_p);
338339

339340
SessionNegotiator* sessionNegotiator = new (*d_allocator_p)
@@ -547,8 +548,8 @@ void Application::stop()
547548
STOP_OBJ(d_domainManager_mp, "DomainManager");
548549
STOP_OBJ(d_dispatcher_mp, "Dispatcher");
549550
STOP_OBJ(d_configProvider_mp, "ConfigProvider");
550-
STOP_OBJ(d_statController_mp, "StatController");
551551
STOP_OBJ(d_authenticationController_mp, "AuthenticationController");
552+
STOP_OBJ(d_statController_mp, "StatController");
552553
STOP_OBJ(d_pluginManager_mp, "PluginManager");
553554

554555
// and now DESTROY everything
@@ -557,8 +558,8 @@ void Application::stop()
557558
DESTROY_OBJ(d_transportManager_mp, "TransportManager");
558559
DESTROY_OBJ(d_dispatcher_mp, "Dispatcher");
559560
DESTROY_OBJ(d_configProvider_mp, "ConfigProvider");
560-
DESTROY_OBJ(d_statController_mp, "StatController");
561561
DESTROY_OBJ(d_authenticationController_mp, "AuthenticationController");
562+
DESTROY_OBJ(d_statController_mp, "StatController");
562563
DESTROY_OBJ(d_pluginManager_mp, "PluginManager");
563564

564565
BALL_LOG_INFO << "BMQbrkr stopped";

src/groups/mqb/mqba/mqba_authenticator.cpp

Lines changed: 140 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,24 @@
2929
#include <mqbblp_clustercatalog.h>
3030
#include <mqbnet_authenticationcontext.h>
3131
#include <mqbnet_initialconnectioncontext.h>
32+
#include <mqbplug_authenticator.h>
3233

3334
// BMQ
3435
#include <bmqio_status.h>
3536
#include <bmqp_ctrlmsg_messages.h>
3637
#include <bmqp_protocol.h>
3738
#include <bmqp_schemaeventbuilder.h>
39+
#include <bmqsys_threadutil.h>
3840
#include <bmqu_memoutstream.h>
3941

4042
// BDE
4143
#include <ball_log.h>
4244
#include <bdlma_sequentialallocator.h>
45+
#include <bdlmt_threadpool.h>
4346
#include <bsl_memory.h>
4447
#include <bsl_ostream.h>
48+
#include <bsls_nullptr.h>
49+
#include <bsls_timeinterval.h>
4550

4651
namespace BloombergLP {
4752
namespace mqba {
@@ -62,6 +67,13 @@ int Authenticator::onAuthenticationRequest(
6267
const bmqp_ctrlmsg::AuthenticationMessage& authenticationMsg,
6368
const InitialConnectionContextSp& context)
6469
{
70+
enum RcEnum {
71+
// Value for the various RC error categories
72+
rc_SUCCESS = 0,
73+
rc_AUTHENTICATING_IN_PROGRESS = -1,
74+
rc_FAIL_TO_ENQUEUE_JOB = -2,
75+
};
76+
6577
// PRECONDITIONS
6678
BSLS_ASSERT_SAFE(authenticationMsg.isAuthenticateRequestValue());
6779
BSLS_ASSERT_SAFE(context->isIncoming());
@@ -70,10 +82,6 @@ int Authenticator::onAuthenticationRequest(
7082
<< context->channel()->peerUri()
7183
<< "': " << authenticationMsg;
7284

73-
bmqp_ctrlmsg::AuthenticationMessage authenticationResponse;
74-
bmqp_ctrlmsg::AuthenticateResponse& response =
75-
authenticationResponse.makeAuthenticateResponse();
76-
7785
// Create an AuthenticationContext for that connection
7886
bsl::shared_ptr<mqbnet::AuthenticationContext> authenticationContext =
7987
bsl::allocate_shared<mqbnet::AuthenticationContext>(
@@ -85,22 +93,18 @@ int Authenticator::onAuthenticationRequest(
8593
);
8694

8795
context->setAuthenticationContext(authenticationContext);
96+
authenticationContext->setInitialConnectionContext(context.get());
8897

89-
// Always succeeds for now
90-
// TODO: For later implementation, plugins will perform authentication,
91-
// taking the `AuthenticationContext` and updates it with the
92-
// authentication result.
93-
response.status().category() = bmqp_ctrlmsg::StatusCategory::E_SUCCESS;
94-
response.status().code() = 0;
95-
response.lifetimeMs() = 10 * 60 * 1000;
96-
97-
authenticationContext->state().testAndSwap(
98-
mqbnet::AuthenticationContext::State::e_AUTHENTICATING,
99-
mqbnet::AuthenticationContext::State::e_AUTHENTICATED);
98+
// Authenticate
99+
int rc = d_threadPool.enqueueJob(
100+
bdlf::BindUtil::bind(&Authenticator::authenticate, this, context));
100101

101-
int rc = sendAuthenticationMessage(errorDescription,
102-
authenticationResponse,
103-
authenticationContext);
102+
if (rc != 0) {
103+
errorDescription << "Failed to enqueue authentication job for '"
104+
<< context->channel()->peerUri() << "' [rc: " << rc
105+
<< ", message: " << authenticationMsg << "]";
106+
return rc_FAIL_TO_ENQUEUE_JOB; // RETURN
107+
}
104108

105109
return rc;
106110
}
@@ -118,7 +122,7 @@ int Authenticator::onAuthenticationResponse(
118122
int Authenticator::sendAuthenticationMessage(
119123
bsl::ostream& errorDescription,
120124
const bmqp_ctrlmsg::AuthenticationMessage& message,
121-
const AuthenticationContextSp& context)
125+
const InitialConnectionContextSp& context)
122126
{
123127
enum RcEnum {
124128
// Value for the various RC error categories
@@ -127,12 +131,10 @@ int Authenticator::sendAuthenticationMessage(
127131
rc_WRITE_FAILURE = -2
128132
};
129133

130-
bmqp::EncodingType::Enum encodingType = bmqp::EncodingType::e_BER;
131-
132134
bdlma::LocalSequentialAllocator<2048> localAllocator(d_allocator_p);
133135

134136
bmqp::SchemaEventBuilder builder(d_blobSpPool_p,
135-
encodingType,
137+
context->authenticationEncodingType(),
136138
&localAllocator);
137139

138140
int rc = builder.setMessage(message, bmqp::EventType::e_AUTHENTICATION);
@@ -144,8 +146,9 @@ int Authenticator::sendAuthenticationMessage(
144146

145147
// Send response event
146148
bmqio::Status status;
147-
context->initialConnectionContext()->channel()->write(&status,
148-
*builder.blob());
149+
150+
context->channel()->write(&status, *builder.blob());
151+
149152
if (!status) {
150153
errorDescription << "Failed sending AuthenticationMessage "
151154
<< "[status: " << status << ", message: " << message
@@ -162,11 +165,104 @@ void Authenticator::initiateOutboundAuthentication(
162165
BALL_LOG_ERROR << "Not Implemented";
163166
}
164167

168+
void Authenticator::authenticate(const InitialConnectionContextSp& context)
169+
{
170+
// PRECONDITIONS
171+
BSLS_ASSERT(context->authenticationContext());
172+
BSLS_ASSERT(context->authenticationContext()->initialConnectionContext());
173+
174+
const bmqp_ctrlmsg::AuthenticateRequest& authenticateRequest =
175+
context->authenticationContext()
176+
->authenticationMessage()
177+
.authenticateRequest();
178+
179+
bsl::shared_ptr<mqbplug::AuthenticationResult> result;
180+
mqbplug::AuthenticationData authenticationData(
181+
authenticateRequest.data().value(),
182+
context->channel()->peerUri());
183+
184+
bmqp_ctrlmsg::AuthenticationMessage authenticationResponse;
185+
bmqp_ctrlmsg::AuthenticateResponse& response =
186+
authenticationResponse.makeAuthenticateResponse();
187+
188+
bmqu::MemOutStream authenticationErrorStream;
189+
190+
BALL_LOG_INFO << "Authenticating connection '"
191+
<< context->channel()->peerUri() << "' with mechanism '"
192+
<< authenticateRequest.mechanism() << "'";
193+
194+
const int authn_rc = d_authnController_p->authenticate(
195+
authenticationErrorStream,
196+
&result,
197+
authenticateRequest.mechanism(),
198+
authenticationData);
199+
if (authn_rc != 0) {
200+
BALL_LOG_ERROR << "Authentication failed for connection '"
201+
<< context->channel()->peerUri() << "' with mechanism '"
202+
<< authenticateRequest.mechanism()
203+
<< "' [rc: " << authn_rc
204+
<< ", error: " << authenticationErrorStream.str()
205+
<< "]";
206+
207+
response.status().code() = authn_rc;
208+
response.status().category() = bmqp_ctrlmsg::StatusCategory::E_REFUSED;
209+
response.status().message() = authenticationErrorStream.str();
210+
211+
context->setAuthenticationContext(bsl::nullptr_t());
212+
}
213+
else {
214+
response.status().code() = 0;
215+
response.status().category() = bmqp_ctrlmsg::StatusCategory::E_SUCCESS;
216+
response.lifetimeMs() = result->lifetimeMs();
217+
218+
context->authenticationContext()->setAuthenticationResult(result);
219+
220+
context->authenticationContext()->state().testAndSwap(
221+
State::e_AUTHENTICATING,
222+
State::e_AUTHENTICATED);
223+
}
224+
225+
bmqu::MemOutStream sendResponseErrorStream;
226+
227+
const int send_rc = sendAuthenticationMessage(sendResponseErrorStream,
228+
authenticationResponse,
229+
context);
230+
231+
// TODO: if we close channel here, for initial connection, we won't be able
232+
// to logOpenSessionTime
233+
// Maybe this shoule be a callback. So can be triggered under different
234+
// senarios
235+
if (authn_rc != 0) {
236+
bmqio::Status status(bmqio::StatusCategory::e_GENERIC_ERROR,
237+
"AuthenticationError",
238+
authn_rc,
239+
d_allocator_p);
240+
context->channel()->close(status);
241+
}
242+
else if (send_rc != 0) {
243+
BALL_LOG_ERROR << sendResponseErrorStream.str();
244+
245+
bmqio::Status status(bmqio::StatusCategory::e_GENERIC_ERROR,
246+
"AuthenticationError",
247+
send_rc,
248+
d_allocator_p);
249+
context->channel()->close(status);
250+
}
251+
}
252+
165253
// CREATORS
166-
Authenticator::Authenticator(BlobSpPool* blobSpPool,
167-
bslma::Allocator* allocator)
168-
: d_allocator_p(allocator)
254+
Authenticator::Authenticator(
255+
mqbauthn::AuthenticationController* authnController,
256+
BlobSpPool* blobSpPool,
257+
bslma::Allocator* allocator)
258+
: d_authnController_p(authnController)
259+
, d_threadPool(bmqsys::ThreadUtil::defaultAttributes(),
260+
0, // min threads
261+
100, // max threads
262+
bsls::TimeInterval(120).totalMilliseconds(), // idle time
263+
allocator)
169264
, d_blobSpPool_p(blobSpPool)
265+
, d_allocator_p(allocator)
170266
{
171267
// NOTHING
172268
}
@@ -177,6 +273,23 @@ Authenticator::~Authenticator()
177273
// NOTHING: (required because of inheritance)
178274
}
179275

276+
int Authenticator::start(bsl::ostream& errorDescription)
277+
{
278+
int rc = d_threadPool.start();
279+
if (rc != 0) {
280+
errorDescription << "Failed to start thread pool for Authenticator"
281+
<< "[rc: " << rc << "]";
282+
return rc; // RETURN
283+
}
284+
285+
return 0;
286+
}
287+
288+
void Authenticator::stop()
289+
{
290+
d_threadPool.stop();
291+
}
292+
180293
int Authenticator::handleAuthentication(
181294
bsl::ostream& errorDescription,
182295
bool* isContinueRead,

0 commit comments

Comments
 (0)