Skip to content

Commit 4c54867

Browse files
author
Jan VL
committed
feat(auth): add MQTT username/password authentication support
1 parent 0dbb6c3 commit 4c54867

8 files changed

Lines changed: 158 additions & 2 deletions

File tree

‎include/sparkplug/host_application.hpp‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ class HostApplication {
8484
bool clean_session = true; ///< MQTT clean session flag
8585
int keep_alive_interval = 60; ///< MQTT keep-alive interval in seconds (default: 60)
8686
std::optional<TlsOptions> tls{}; ///< TLS/SSL options (required if broker_url uses ssl://)
87+
std::optional<std::string> username{}; ///< MQTT username for authentication (optional)
88+
std::optional<std::string> password{}; ///< MQTT password for authentication (optional)
8789
};
8890

8991
/**
@@ -106,6 +108,16 @@ class HostApplication {
106108
HostApplication(HostApplication&&) noexcept;
107109
HostApplication& operator=(HostApplication&&) noexcept;
108110

111+
/**
112+
* @brief Sets MQTT username and password for authentication.
113+
*
114+
* @param username MQTT username (empty string or std::nullopt to unset)
115+
* @param password MQTT password (empty string or std::nullopt to unset)
116+
*
117+
* @note Must be called before connect().
118+
*/
119+
void set_credentials(std::optional<std::string> username, std::optional<std::string> password);
120+
109121
/**
110122
* @brief Connects to the MQTT broker.
111123
*

‎include/sparkplug/publisher.hpp‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ class Publisher {
111111
int death_qos = 1; ///< MQTT QoS for NDEATH Will Message. Sparkplug requires 1.
112112
bool clean_session = true; ///< MQTT clean session flag
113113
int keep_alive_interval = 60; ///< MQTT keep-alive interval in seconds (Sparkplug recommends 60)
114-
std::optional<TlsOptions> tls{}; ///< TLS/SSL options (required if broker_url uses ssl://)
114+
std::optional<TlsOptions> tls{}; ///< TLS/SSL options (required if broker_url uses ssl://)
115+
std::optional<std::string> username{}; ///< MQTT username for authentication (optional)
116+
std::optional<std::string> password{}; ///< MQTT password for authentication (optional)
115117
std::optional<CommandCallback>
116118
command_callback{}; ///< Optional callback for NCMD messages (subscribed before NBIRTH)
117119
};
@@ -136,6 +138,16 @@ class Publisher {
136138
Publisher(Publisher&&) noexcept;
137139
Publisher& operator=(Publisher&&) noexcept;
138140

141+
/**
142+
* @brief Sets MQTT username and password for authentication.
143+
*
144+
* @param username MQTT username (empty string or std::nullopt to unset)
145+
* @param password MQTT password (empty string or std::nullopt to unset)
146+
*
147+
* @note Must be called before connect().
148+
*/
149+
void set_credentials(std::optional<std::string> username, std::optional<std::string> password);
150+
139151
/**
140152
* @brief Connects to the MQTT broker and establishes a Sparkplug B session.
141153
*

‎include/sparkplug/sparkplug_c.h‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,19 @@ sparkplug_publisher_t* sparkplug_publisher_create(const char* broker_url, const
146146
*/
147147
void sparkplug_publisher_destroy(sparkplug_publisher_t* pub);
148148

149+
/**
150+
* @brief Sets MQTT username and password for authentication.
151+
*
152+
* @param pub Publisher handle
153+
* @param username MQTT username (may be NULL to unset)
154+
* @param password MQTT password (may be NULL to unset)
155+
* @return 0 on success, -1 on failure
156+
*
157+
* @note Must be called before sparkplug_publisher_connect().
158+
*/
159+
int sparkplug_publisher_set_credentials(sparkplug_publisher_t* pub, const char* username,
160+
const char* password);
161+
149162
/**
150163
* @brief Connects the publisher to the MQTT broker.
151164
*
@@ -386,6 +399,19 @@ sparkplug_host_application_t* sparkplug_host_application_create(const char* brok
386399
*/
387400
void sparkplug_host_application_destroy(sparkplug_host_application_t* host);
388401

402+
/**
403+
* @brief Sets MQTT username and password for authentication.
404+
*
405+
* @param host Host Application handle
406+
* @param username MQTT username (may be NULL to unset)
407+
* @param password MQTT password (may be NULL to unset)
408+
* @return 0 on success, -1 on failure
409+
*
410+
* @note Must be called before sparkplug_host_application_connect().
411+
*/
412+
int sparkplug_host_application_set_credentials(sparkplug_host_application_t* host,
413+
const char* username, const char* password);
414+
389415
/**
390416
* @brief Connects the Host Application to the MQTT broker.
391417
*
@@ -500,6 +526,19 @@ sparkplug_subscriber_t* sparkplug_subscriber_create(const char* broker_url, cons
500526
*/
501527
void sparkplug_subscriber_destroy(sparkplug_subscriber_t* sub);
502528

529+
/**
530+
* @brief Sets MQTT username and password for authentication.
531+
*
532+
* @param sub Subscriber handle
533+
* @param username MQTT username (may be NULL to unset)
534+
* @param password MQTT password (may be NULL to unset)
535+
* @return 0 on success, -1 on failure
536+
*
537+
* @note Must be called before sparkplug_subscriber_connect().
538+
*/
539+
int sparkplug_subscriber_set_credentials(sparkplug_subscriber_t* sub, const char* username,
540+
const char* password);
541+
503542
/**
504543
* @brief Connects the subscriber to the MQTT broker.
505544
*

‎include/sparkplug/subscriber.hpp‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,9 @@ class Subscriber {
170170
bool clean_session = true; ///< MQTT clean session flag
171171
bool validate_sequence = true; ///< Enable sequence number validation (detects packet loss)
172172
std::optional<TlsOptions> tls{}; ///< TLS/SSL options (required if broker_url uses ssl://)
173-
LogCallback log_callback{}; ///< Optional callback for library log messages
173+
std::optional<std::string> username{}; ///< MQTT username for authentication (optional)
174+
std::optional<std::string> password{}; ///< MQTT password for authentication (optional)
175+
LogCallback log_callback{}; ///< Optional callback for library log messages
174176
};
175177

176178
/**
@@ -239,6 +241,16 @@ class Subscriber {
239241
Subscriber(Subscriber&&) noexcept;
240242
Subscriber& operator=(Subscriber&&) noexcept;
241243

244+
/**
245+
* @brief Sets MQTT username and password for authentication.
246+
*
247+
* @param username MQTT username (empty string or std::nullopt to unset)
248+
* @param password MQTT password (empty string or std::nullopt to unset)
249+
*
250+
* @note Must be called before connect().
251+
*/
252+
void set_credentials(std::optional<std::string> username, std::optional<std::string> password);
253+
242254
/**
243255
* @brief Connects to the MQTT broker.
244256
*

‎src/c_bindings.cpp‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@ void sparkplug_publisher_destroy(sparkplug_publisher_t* pub) {
162162
delete pub;
163163
}
164164

165+
int sparkplug_publisher_set_credentials(sparkplug_publisher_t* pub, const char* username,
166+
const char* password) {
167+
if (!pub) {
168+
return -1;
169+
}
170+
171+
std::optional<std::string> user = username ? std::optional<std::string>(username) : std::nullopt;
172+
std::optional<std::string> pass = password ? std::optional<std::string>(password) : std::nullopt;
173+
pub->impl.set_credentials(std::move(user), std::move(pass));
174+
return 0;
175+
}
176+
165177
int sparkplug_publisher_connect(sparkplug_publisher_t* pub) {
166178
if (!pub)
167179
return -1;
@@ -371,6 +383,18 @@ void sparkplug_subscriber_destroy(sparkplug_subscriber_t* sub) {
371383
delete sub;
372384
}
373385

386+
int sparkplug_subscriber_set_credentials(sparkplug_subscriber_t* sub, const char* username,
387+
const char* password) {
388+
if (!sub || !sub->impl) {
389+
return -1;
390+
}
391+
392+
std::optional<std::string> user = username ? std::optional<std::string>(username) : std::nullopt;
393+
std::optional<std::string> pass = password ? std::optional<std::string>(password) : std::nullopt;
394+
sub->impl->set_credentials(std::move(user), std::move(pass));
395+
return 0;
396+
}
397+
374398
int sparkplug_subscriber_connect(sparkplug_subscriber_t* sub) {
375399
if (!sub || !sub->impl)
376400
return -1;
@@ -835,6 +859,18 @@ void sparkplug_host_application_destroy(sparkplug_host_application_t* host) {
835859
delete host;
836860
}
837861

862+
int sparkplug_host_application_set_credentials(sparkplug_host_application_t* host,
863+
const char* username, const char* password) {
864+
if (!host) {
865+
return -1;
866+
}
867+
868+
std::optional<std::string> user = username ? std::optional<std::string>(username) : std::nullopt;
869+
std::optional<std::string> pass = password ? std::optional<std::string>(password) : std::nullopt;
870+
host->impl.set_credentials(std::move(user), std::move(pass));
871+
return 0;
872+
}
873+
838874
int sparkplug_host_application_connect(sparkplug_host_application_t* host) {
839875
if (!host) {
840876
return -1;

‎src/host_application.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ HostApplication& HostApplication::operator=(HostApplication&& other) noexcept {
7676
return *this;
7777
}
7878

79+
void HostApplication::set_credentials(std::optional<std::string> username,
80+
std::optional<std::string> password) {
81+
std::lock_guard<std::mutex> lock(mutex_);
82+
config_.username = std::move(username);
83+
config_.password = std::move(password);
84+
}
85+
7986
std::expected<void, std::string> HostApplication::connect() {
8087
std::lock_guard<std::mutex> lock(mutex_);
8188

@@ -91,6 +98,14 @@ std::expected<void, std::string> HostApplication::connect() {
9198
conn_opts.keepAliveInterval = config_.keep_alive_interval;
9299
conn_opts.cleansession = config_.clean_session;
93100

101+
// Set credentials if provided
102+
if (config_.username.has_value()) {
103+
conn_opts.username = config_.username.value().c_str();
104+
}
105+
if (config_.password.has_value()) {
106+
conn_opts.password = config_.password.value().c_str();
107+
}
108+
94109
MQTTAsync_SSLOptions ssl_opts = MQTTAsync_SSLOptions_initializer;
95110
if (config_.tls.has_value()) {
96111
const auto& tls = config_.tls.value();

‎src/publisher.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@ Publisher& Publisher::operator=(Publisher&& other) noexcept {
146146
return *this;
147147
}
148148

149+
void Publisher::set_credentials(std::optional<std::string> username,
150+
std::optional<std::string> password) {
151+
std::lock_guard<std::mutex> lock(mutex_);
152+
config_.username = std::move(username);
153+
config_.password = std::move(password);
154+
}
155+
149156
std::expected<void, std::string> Publisher::connect() {
150157
std::lock_guard<std::mutex> lock(mutex_);
151158

@@ -166,6 +173,14 @@ std::expected<void, std::string> Publisher::connect() {
166173
conn_opts.keepAliveInterval = config_.keep_alive_interval;
167174
conn_opts.cleansession = config_.clean_session;
168175

176+
// Set credentials if provided
177+
if (config_.username.has_value()) {
178+
conn_opts.username = config_.username.value().c_str();
179+
}
180+
if (config_.password.has_value()) {
181+
conn_opts.password = config_.password.value().c_str();
182+
}
183+
169184
// Setup TLS/SSL if configured
170185
MQTTAsync_SSLOptions ssl_opts = MQTTAsync_SSLOptions_initializer;
171186
if (config_.tls.has_value()) {

‎src/subscriber.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ static void on_connection_lost(void* context, char* cause) {
337337
}
338338
}
339339

340+
void Subscriber::set_credentials(std::optional<std::string> username,
341+
std::optional<std::string> password) {
342+
std::lock_guard<std::mutex> lock(mutex_);
343+
config_.username = std::move(username);
344+
config_.password = std::move(password);
345+
}
346+
340347
std::expected<void, std::string> Subscriber::connect() {
341348
std::lock_guard<std::mutex> lock(mutex_);
342349

@@ -360,6 +367,14 @@ std::expected<void, std::string> Subscriber::connect() {
360367
conn_opts.keepAliveInterval = DEFAULT_KEEP_ALIVE_INTERVAL;
361368
conn_opts.cleansession = config_.clean_session;
362369

370+
// Set credentials if provided
371+
if (config_.username.has_value()) {
372+
conn_opts.username = config_.username.value().c_str();
373+
}
374+
if (config_.password.has_value()) {
375+
conn_opts.password = config_.password.value().c_str();
376+
}
377+
363378
MQTTAsync_SSLOptions ssl_opts = MQTTAsync_SSLOptions_initializer;
364379
if (config_.tls.has_value()) {
365380
const auto& tls = config_.tls.value();

0 commit comments

Comments
 (0)