Files
magistrala/users/middleware/logging.go
T
Felix Gateru 9c2608659f SMQ-1672 - Revoke refresh token (#3241)
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Co-authored-by: nyagamunene <stevenyaga2014@gmail.com>
2026-03-03 15:22:28 +01:00

563 lines
21 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package middleware
import (
"context"
"log/slog"
"time"
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
"github.com/absmach/supermq/pkg/authn"
"github.com/absmach/supermq/users"
"github.com/go-chi/chi/v5/middleware"
)
var _ users.Service = (*loggingMiddleware)(nil)
type loggingMiddleware struct {
logger *slog.Logger
svc users.Service
}
// NewLogging adds logging facilities to the users service.
func NewLogging(svc users.Service, logger *slog.Logger) users.Service {
return &loggingMiddleware{logger, svc}
}
// Register logs the user request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) Register(ctx context.Context, session authn.Session, user users.User, selfRegister bool) (u users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("username", user.Credentials.Username),
slog.String("first_name", user.FirstName),
slog.String("last_name", user.LastName),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Register user failed", args...)
return
}
args = append(args, slog.String("user_id", u.ID))
lm.logger.Info("Register user completed successfully", args...)
}(time.Now())
return lm.svc.Register(ctx, session, user, selfRegister)
}
// SendVerification logs the send_verification request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) SendVerification(ctx context.Context, session authn.Session) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Send verification failed", args...)
return
}
lm.logger.Info("Send verification completed successfully", args...)
}(time.Now())
return lm.svc.SendVerification(ctx, session)
}
// VerifyEmail logs the verify_email request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) VerifyEmail(ctx context.Context, verificationToken string) (user users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("user_id", user.ID),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Verify email failed", args...)
return
}
lm.logger.Info("Verify email completed successfully", args...)
}(time.Now())
return lm.svc.VerifyEmail(ctx, verificationToken)
}
// IssueToken logs the issue_token request. It logs the username type and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) IssueToken(ctx context.Context, username, secret, description string) (t *grpcTokenV1.Token, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if t.AccessType != "" {
args = append(args, slog.String("access_type", t.AccessType))
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Issue token failed", args...)
return
}
lm.logger.Info("Issue token completed successfully", args...)
}(time.Now())
return lm.svc.IssueToken(ctx, username, secret, description)
}
// RefreshToken logs the refresh_token request. It logs the refreshtoken, token type and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) RefreshToken(ctx context.Context, session authn.Session, refreshToken string) (t *grpcTokenV1.Token, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if t.AccessType != "" {
args = append(args, slog.String("access_type", t.AccessType))
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Refresh token failed", args...)
return
}
lm.logger.Info("Refresh token completed successfully", args...)
}(time.Now())
return lm.svc.RefreshToken(ctx, session, refreshToken)
}
// RevokeRefreshToken logs the revoke_refresh_token request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) RevokeRefreshToken(ctx context.Context, session authn.Session, tokenID string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Revoke refresh token failed", args...)
return
}
lm.logger.Info("Revoke refresh token completed successfully", args...)
}(time.Now())
return lm.svc.RevokeRefreshToken(ctx, session, tokenID)
}
// ListActiveRefreshTokens logs the list_active_refresh_tokens request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) ListActiveRefreshTokens(ctx context.Context, session authn.Session) (tokens *grpcTokenV1.ListUserRefreshTokensRes, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if tokens != nil {
args = append(args, slog.Int("tokens_count", len(tokens.GetRefreshTokens())))
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("List active refresh tokens failed", args...)
return
}
lm.logger.Info("List active refresh tokens completed successfully", args...)
}(time.Now())
return lm.svc.ListActiveRefreshTokens(ctx, session)
}
// View logs the view_user request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) View(ctx context.Context, session authn.Session, id string) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", id),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("View user failed", args...)
return
}
lm.logger.Info("View user completed successfully", args...)
}(time.Now())
return lm.svc.View(ctx, session, id)
}
// ViewProfile logs the view_profile request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) ViewProfile(ctx context.Context, session authn.Session) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", c.ID),
slog.String("username", c.Credentials.Username),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("View profile failed", args...)
return
}
lm.logger.Info("View profile completed successfully", args...)
}(time.Now())
return lm.svc.ViewProfile(ctx, session)
}
// ListUsers logs the list_users request. It logs the page metadata and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) ListUsers(ctx context.Context, session authn.Session, pm users.Page) (cp users.UsersPage, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("page",
slog.Uint64("limit", pm.Limit),
slog.Uint64("offset", pm.Offset),
slog.Uint64("total", cp.Total),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("List users failed", args...)
return
}
lm.logger.Info("List users completed successfully", args...)
}(time.Now())
return lm.svc.ListUsers(ctx, session, pm)
}
// SearchUsers logs the search_users request. It logs the page metadata and the time it took to complete the request.
func (lm *loggingMiddleware) SearchUsers(ctx context.Context, cp users.Page) (mp users.UsersPage, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("page",
slog.Uint64("limit", cp.Limit),
slog.Uint64("offset", cp.Offset),
slog.Uint64("total", mp.Total),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Search users failed to complete successfully", args...)
return
}
lm.logger.Info("Search users completed successfully", args...)
}(time.Now())
return lm.svc.SearchUsers(ctx, cp)
}
// Update logs the update_user request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) Update(ctx context.Context, session authn.Session, id string, user users.UserReq) (u users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", u.ID),
slog.String("username", u.Credentials.Username),
slog.String("first_name", u.FirstName),
slog.String("last_name", u.LastName),
slog.Any("metadata", u.Metadata),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update user failed", args...)
return
}
lm.logger.Info("Update user completed successfully", args...)
}(time.Now())
return lm.svc.Update(ctx, session, id, user)
}
// UpdateTags logs the update_user_tags request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateTags(ctx context.Context, session authn.Session, id string, user users.UserReq) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", c.ID),
slog.Any("tags", c.Tags),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update user tags failed", args...)
return
}
lm.logger.Info("Update user tags completed successfully", args...)
}(time.Now())
return lm.svc.UpdateTags(ctx, session, id, user)
}
// UpdateEmail logs the update_user_email request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateEmail(ctx context.Context, session authn.Session, id, email string) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", c.ID),
slog.String("email", c.Email),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update user email failed", args...)
return
}
lm.logger.Info("Update user email completed successfully", args...)
}(time.Now())
return lm.svc.UpdateEmail(ctx, session, id, email)
}
// UpdateSecret logs the update_user_secret request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateSecret(ctx context.Context, session authn.Session, oldSecret, newSecret string) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", c.ID),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update user secret failed", args...)
return
}
lm.logger.Info("Update user secret completed successfully", args...)
}(time.Now())
return lm.svc.UpdateSecret(ctx, session, oldSecret, newSecret)
}
// UpdateUsername logs the update_usernames request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateUsername(ctx context.Context, session authn.Session, id, username string) (u users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", u.ID),
slog.String("username", u.Credentials.Username),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update user names failed", args...)
return
}
lm.logger.Info("Update user names completed successfully", args...)
}(time.Now())
return lm.svc.UpdateUsername(ctx, session, id, username)
}
// UpdateProfilePicture logs the update_profile_picture request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateProfilePicture(ctx context.Context, session authn.Session, id string, user users.UserReq) (u users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", u.ID),
slog.String("profile_picture", u.ProfilePicture),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update profile picture failed", args...)
return
}
lm.logger.Info("Update profile picture completed successfully", args...)
}(time.Now())
return lm.svc.UpdateProfilePicture(ctx, session, id, user)
}
// SendPasswordReset logs the send_password_reset request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) SendPasswordReset(ctx context.Context, email string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Generate reset token failed", args...)
return
}
lm.logger.Info("Send password reset completed successfully", args...)
}(time.Now())
return lm.svc.SendPasswordReset(ctx, email)
}
// ResetSecret logs the reset_secret request. It logs the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) ResetSecret(ctx context.Context, session authn.Session, secret string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Reset secret failed", args...)
return
}
lm.logger.Info("Reset secret completed successfully", args...)
}(time.Now())
return lm.svc.ResetSecret(ctx, session, secret)
}
// UpdateRole logs the update_user_role request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) UpdateRole(ctx context.Context, session authn.Session, user users.User) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", user.ID),
slog.String("role", user.Role.String()),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Update user role failed", args...)
return
}
lm.logger.Info("Update user role completed successfully", args...)
}(time.Now())
return lm.svc.UpdateRole(ctx, session, user)
}
// Enable logs the enable_user request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) Enable(ctx context.Context, session authn.Session, id string) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", id),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Enable user failed", args...)
return
}
lm.logger.Info("Enable user completed successfully", args...)
}(time.Now())
return lm.svc.Enable(ctx, session, id)
}
// Disable logs the disable_user request. It logs the user id and the time it took to complete the request.
// If the request fails, it logs the error.
func (lm *loggingMiddleware) Disable(ctx context.Context, session authn.Session, id string) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.Group("user",
slog.String("id", id),
),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Disable user failed", args...)
return
}
lm.logger.Info("Disable user completed successfully", args...)
}(time.Now())
return lm.svc.Disable(ctx, session, id)
}
// Identify logs the identify request. It logs the time it took to complete the request.
func (lm *loggingMiddleware) Identify(ctx context.Context, session authn.Session) (id string, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.String("user_id", id),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Identify user failed", args...)
return
}
lm.logger.Info("Identify user completed successfully", args...)
}(time.Now())
return lm.svc.Identify(ctx, session)
}
func (lm *loggingMiddleware) OAuthCallback(ctx context.Context, user users.User) (c users.User, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.String("user_id", user.ID),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("OAuth callback failed", args...)
return
}
lm.logger.Info("OAuth callback completed successfully", args...)
}(time.Now())
return lm.svc.OAuthCallback(ctx, user)
}
// Delete logs the delete_user request. It logs the user id and token and the time it took to complete the request.
func (lm *loggingMiddleware) Delete(ctx context.Context, session authn.Session, id string) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.String("user_id", id),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Delete user failed to complete successfully", args...)
return
}
lm.logger.Info("Delete user completed successfully", args...)
}(time.Now())
return lm.svc.Delete(ctx, session, id)
}
// OAuthAddUserPolicy logs the add_user_policy request. It logs the user id and the time it took to complete the request.
func (lm *loggingMiddleware) OAuthAddUserPolicy(ctx context.Context, user users.User) (err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.String("request_id", middleware.GetReqID(ctx)),
slog.String("user_id", user.ID),
}
if err != nil {
args = append(args, slog.String("error", err.Error()))
lm.logger.Warn("Add user policy failed", args...)
return
}
lm.logger.Info("Add user policy completed successfully", args...)
}(time.Now())
return lm.svc.OAuthAddUserPolicy(ctx, user)
}