test: enable mosquitto password auth; add mqttping endpoint; use credentials in subscriber; publish defaults

This commit is contained in:
2025-12-28 15:24:12 +01:00
parent 8fd9353068
commit c835fb7a98
5 changed files with 86 additions and 41 deletions
+18 -2
View File
@@ -13,10 +13,11 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.piskot.si/SeminarM2/lambdaiot-core/internal/config" "git.piskot.si/SeminarM2/lambdaiot-core/internal/config"
mqttclient "git.piskot.si/SeminarM2/lambdaiot-core/internal/mqtt"
"git.piskot.si/SeminarM2/lambdaiot-core/internal/handler" "git.piskot.si/SeminarM2/lambdaiot-core/internal/handler"
"git.piskot.si/SeminarM2/lambdaiot-core/internal/middleware" "git.piskot.si/SeminarM2/lambdaiot-core/internal/middleware"
mqttclient "git.piskot.si/SeminarM2/lambdaiot-core/internal/mqtt"
) )
func main() { func main() {
// load configuration (look for ./config.toml by default) // load configuration (look for ./config.toml by default)
cfg, err := config.Load("") cfg, err := config.Load("")
@@ -41,6 +42,7 @@ func main() {
log.Printf("warning: mqtt connect failed: %v", err) log.Printf("warning: mqtt connect failed: %v", err)
} else { } else {
mq = mqc mq = mqc
mqttclient.SetDefault(mqc)
// publish a startup message (non-blocking) // publish a startup message (non-blocking)
go func() { go func() {
msg := fmt.Sprintf("lambdaiot-core started on %s", addr) msg := fmt.Sprintf("lambdaiot-core started on %s", addr)
@@ -51,7 +53,7 @@ func main() {
} }
} }
// mqttping endpoint will be added after router initialization
// Gin setup // Gin setup
r := gin.New() r := gin.New()
@@ -63,6 +65,20 @@ func main() {
r.GET("/hello", handler.Hello) r.GET("/hello", handler.Hello)
r.POST("/login", handler.Login) r.POST("/login", handler.Login)
// mqttping endpoint: publish current timestamp to MQTT topic
r.POST("/mqttping", func(c *gin.Context) {
ts := time.Now().Format(time.RFC3339)
if mq == nil {
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "mqtt not connected"})
return
}
if err := mq.Publish(cfg.MQTT.Topic, []byte(ts)); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"timestamp": ts})
})
// Protected routes // Protected routes
auth := r.Group("/") auth := r.Group("/")
auth.Use(middleware.AuthMiddleware(cfg.Server.JWTSecret)) auth.Use(middleware.AuthMiddleware(cfg.Server.JWTSecret))
+17 -1
View File
@@ -4,14 +4,30 @@ import (
"fmt" "fmt"
"time" "time"
paho "github.com/eclipse/paho.mqtt.golang"
"git.piskot.si/SeminarM2/lambdaiot-core/internal/config" "git.piskot.si/SeminarM2/lambdaiot-core/internal/config"
paho "github.com/eclipse/paho.mqtt.golang"
) )
type Client struct { type Client struct {
client paho.Client client paho.Client
} }
// Default is a package-level client used by helpers
var Default *Client
// SetDefault sets the package default client
func SetDefault(c *Client) {
Default = c
}
// PublishDefault publishes using the default client
func PublishDefault(topic string, payload []byte) error {
if Default == nil {
return fmt.Errorf("no default mqtt client")
}
return Default.Publish(topic, payload)
}
func Connect(cfg config.MQTTConfig) (*Client, error) { func Connect(cfg config.MQTTConfig) (*Client, error) {
opts := paho.NewClientOptions() opts := paho.NewClientOptions()
opts.AddBroker(cfg.Broker) opts.AddBroker(cfg.Broker)
+6
View File
@@ -14,6 +14,8 @@ services:
- MQTT_BROKER=tcp://mosquitto:1883 - MQTT_BROKER=tcp://mosquitto:1883
- MQTT_CLIENT_ID=lambdaiot-server - MQTT_CLIENT_ID=lambdaiot-server
- MQTT_TOPIC=lambdaiot - MQTT_TOPIC=lambdaiot
- MQTT_USERNAME=testuser
- MQTT_PASSWORD=testpass
depends_on: depends_on:
- mosquitto - mosquitto
# server image now waits for MQTT broker itself via entrypoint # server image now waits for MQTT broker itself via entrypoint
@@ -27,6 +29,8 @@ services:
- mosquitto_data:/mosquitto/data - mosquitto_data:/mosquitto/data
- mosquitto_log:/mosquitto/log - mosquitto_log:/mosquitto/log
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro - ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
# ensure a password file exists and start mosquitto with our config
command: sh -c "mosquitto_passwd -b /mosquitto/config/passwordfile testuser testpass >/dev/null 2>&1 || true; /usr/sbin/mosquitto -c /mosquitto/config/mosquitto.conf"
healthcheck: healthcheck:
test: ["CMD", "sh", "-c", "nc -z localhost 1883 || exit 1"] test: ["CMD", "sh", "-c", "nc -z localhost 1883 || exit 1"]
interval: 2s interval: 2s
@@ -41,6 +45,8 @@ services:
environment: environment:
- MQTT_BROKER=mosquitto:1883 - MQTT_BROKER=mosquitto:1883
- MQTT_TOPIC=lambdaiot - MQTT_TOPIC=lambdaiot
- MQTT_USERNAME=testuser
- MQTT_PASSWORD=testpass
command: sh -c "pip install paho-mqtt && python subscribe.py" command: sh -c "pip install paho-mqtt && python subscribe.py"
depends_on: depends_on:
- mosquitto - mosquitto
+4 -1
View File
@@ -1,6 +1,9 @@
# Allow external connections on port 1883 # Allow external connections on port 1883
# listen on all interfaces
listener 1883 0.0.0.0 listener 1883 0.0.0.0
allow_anonymous true # do not allow anonymous in this test stack; require password_file
allow_anonymous false
password_file /mosquitto/config/passwordfile
# Increase persistence location so container can map volume if needed # Increase persistence location so container can map volume if needed
persistence true persistence true
persistence_location /mosquitto/data/ persistence_location /mosquitto/data/
+4
View File
@@ -6,6 +6,8 @@ import paho.mqtt.client as mqtt
broker = os.getenv('MQTT_BROKER', 'localhost:1883') broker = os.getenv('MQTT_BROKER', 'localhost:1883')
topic = os.getenv('MQTT_TOPIC', 'lambdaiot') topic = os.getenv('MQTT_TOPIC', 'lambdaiot')
username = os.getenv('MQTT_USERNAME')
password = os.getenv('MQTT_PASSWORD')
if broker.startswith('tcp://'): if broker.startswith('tcp://'):
broker = broker[len('tcp://'):] broker = broker[len('tcp://'):]
@@ -28,6 +30,8 @@ def on_message(client, userdata, msg):
client = mqtt.Client() client = mqtt.Client()
client.on_connect = on_connect client.on_connect = on_connect
client.on_message = on_message client.on_message = on_message
if username:
client.username_pw_set(username, password)
try: try:
client.connect(host, port, 60) client.connect(host, port, 60)