Skip to content

Commit ea2584f

Browse files
Completed Logging and Authentication Middleware, Testing Logging via JSON
1 parent 3f14ec4 commit ea2584f

File tree

10 files changed

+119
-61
lines changed

10 files changed

+119
-61
lines changed

api/middleware/middleware.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,53 @@
11
package middleware
2+
3+
import (
4+
"net/http"
5+
"time"
6+
7+
"github.com/PythonHacker24/linux-acl-management-backend/internal/authentication"
8+
"go.uber.org/zap"
9+
)
10+
11+
/* logging middleware for http requests */
12+
func LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
13+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14+
start := time.Now()
15+
16+
/* logging recieved request at the instant of receiving */
17+
zap.L().Info("Recieved request",
18+
zap.String("Method", r.Method),
19+
zap.String("Path", r.URL.Path),
20+
)
21+
22+
/* return the handler */
23+
next(w, r)
24+
25+
/* logging time taken by the request */
26+
zap.L().Info("Request completed",
27+
zap.String("Method", r.Method),
28+
zap.String("Path", r.URL.Path),
29+
zap.Duration("Duration", time.Since(start)),
30+
)
31+
})
32+
}
33+
34+
/* authentication middleware for http requests */
35+
func AuthenticationMiddleware(next http.HandlerFunc) http.HandlerFunc {
36+
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
37+
38+
/* authenticate the request through JWT */
39+
username, err := authentication.ExtractUsernameFromRequest(r)
40+
if err != nil {
41+
zap.L().Error("Error during authentication",
42+
zap.Error(err),
43+
)
44+
return
45+
}
46+
47+
/* set the header with the username */
48+
r.Header.Set("X-User", username)
49+
50+
/* return the handler */
51+
next(w, r)
52+
})
53+
}

api/routes/routes.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package routes
33
import (
44
"net/http"
55

6+
"github.com/PythonHacker24/linux-acl-management-backend/api/middleware"
67
"github.com/PythonHacker24/linux-acl-management-backend/internal/handlers"
78
)
89

910
func RegisterRoutes(mux *http.ServeMux) {
10-
mux.Handle("/health", http.HandlerFunc((handlers.HealthHandler)))
11+
mux.Handle("GET /health", http.HandlerFunc(
12+
middleware.LoggingMiddleware(handlers.HealthHandler),
13+
))
1114
}

cmd/laclm/main.go

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"time"
1111

1212
"go.uber.org/zap"
13+
"github.com/spf13/cobra"
14+
"github.com/MakeNowJust/heredoc"
1315

1416
"github.com/PythonHacker24/linux-acl-management-backend/api/routes"
1517
"github.com/PythonHacker24/linux-acl-management-backend/config"
@@ -26,14 +28,47 @@ func exec() error {
2628

2729
/* exec() wraps run() protecting it with user interrupts */
2830

31+
utils.InitLogger(true)
2932
/* zap.L() can be used all over the code for global level logging */
33+
3034
zap.L().Info("Logger Initiated ...")
35+
36+
/* setting up cobra for cli interactions */
37+
var(
38+
configPath string
39+
rootCmd = &cobra.Command{
40+
Use: "laclm <command> <subcommand>",
41+
Short: "Backend server for linux acl management",
42+
Example: heredoc.Doc(`
43+
$ laclm
44+
$ laclm --config /path/to/config.yaml
45+
`),
46+
Run: func(cmd *cobra.Command, args []string) {
47+
if configPath != "" {
48+
fmt.Printf("Using config file: %s\n", configPath)
49+
} else {
50+
fmt.Println("No config file provided.")
51+
}
52+
},
53+
}
54+
)
55+
56+
/* adding --config arguement */
57+
rootCmd.PersistentFlags().StringVar(&configPath, "config", "", "Path to config file")
58+
59+
/* Execute the command */
60+
if err := rootCmd.Execute(); err != nil {
61+
zap.L().Error("arguements error",
62+
zap.Error(err),
63+
)
64+
os.Exit(1)
65+
}
3166

3267
/*
3368
load config file
3469
if there is an error in loading the config file, then it will exit with code 1
3570
*/
36-
config.LoadConfig("./config.yaml")
71+
config.LoadConfig(configPath)
3772

3873
/*
3974
load environment variables
@@ -42,7 +77,6 @@ func exec() error {
4277
config.LoadEnv()
4378

4479
/* true for production, false for development mode */
45-
utils.InitLogger(false)
4680

4781
ctx, cancel := context.WithCancel(context.Background())
4882
defer cancel()

config.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
# backend environment configs
44
app:
5-
name:
6-
version:
7-
environment:
5+
name: laclm-dev
6+
version: v1.1
7+
environment: development
88

99
# backend server deployment configs
1010
server:
11-
host:
12-
port:
11+
host: localhost
12+
port: 8080
1313

1414
# databases for operations
1515
database:

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ go 1.24.2
44

55
require (
66
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
7+
github.com/MakeNowJust/heredoc v1.0.0 // indirect
78
github.com/bufbuild/buf v1.53.0 // indirect
89
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
910
github.com/go-ldap/ldap/v3 v3.4.11 // indirect
1011
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
1112
github.com/google/uuid v1.6.0 // indirect
13+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
14+
github.com/spf13/cobra v1.9.1 // indirect
15+
github.com/spf13/pflag v1.0.6 // indirect
1216
go.uber.org/multierr v1.11.0 // indirect
1317
go.uber.org/zap v1.27.0 // indirect
1418
golang.org/x/crypto v0.37.0 // indirect

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
22
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
3+
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
4+
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
35
github.com/bufbuild/buf v1.53.0 h1:i0OgpDkzv8yLyCokXRCgbQao/SqTnqXYtERre0Jw6Do=
46
github.com/bufbuild/buf v1.53.0/go.mod h1:DylfLDMblZt5mX/SEFv2VzZMgdlePArhMGYVpk4M6N0=
7+
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
58
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
69
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
710
github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU=
@@ -10,6 +13,13 @@ github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeD
1013
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
1114
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
1215
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
16+
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
17+
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
18+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
19+
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
20+
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
21+
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
22+
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
1323
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
1424
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
1525
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=

internal/authentication/authentication.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func GetUsernameFromJWT(tokenString string) (string, error) {
5151
/* get claims from JWT Token */
5252
claims, err := ValidateJWT(tokenString)
5353
if err != nil {
54-
return "", fmt.Errorf("invalid token: %v", err)
54+
return "", err
5555
}
5656

5757
/* extract username from JWT Token */

internal/handlers/handlers.go

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,3 @@ func HealthHandler(w http.ResponseWriter, r *http.Request) {
2424
}
2525
}
2626

27-
/* allows users to create a session */
28-
func LoginHandler(w http.ResponseWriter, r *http.Request) {
29-
var user models.User
30-
31-
/* decode json response*/
32-
err := json.NewDecoder(r.Body).Decode(&user)
33-
if err != nil {
34-
zap.L().Warn("A request with invalid body recieved")
35-
http.Error(w, "Invalid request body", http.StatusBadRequest)
36-
return
37-
}
38-
39-
/* check if username and password exists */
40-
if user.Username == "" || user.Password == "" {
41-
zap.L().Warn("A request with no username or password recieved")
42-
http.Error(w, "Username and password are required", http.StatusBadRequest)
43-
return
44-
}
45-
46-
/* authenticate the user with ldap */
47-
authStatus := ldap.AuthenticateUser()
48-
if !authStatus {
49-
zap.L().Warn("A request with invalid credentials recieved")
50-
http.Error(w, "Invalid credentials", http.StatusUnauthorized)
51-
return
52-
}
53-
54-
/* create a session if user exists */
55-
sessionmanager.CreateSession(user.Username)
56-
57-
/* create a JWT token for the user */
58-
token, err := authentication.GenerateJWT(user.Username)
59-
if err != nil {
60-
zap.L().Error("Error generating token",
61-
zap.Error(err),
62-
)
63-
http.Error(w, "Error generating token", http.StatusInternalServerError)
64-
return
65-
}
66-
67-
/* send response with JWT token to the user */
68-
response := map[string]string{"token": token}
69-
w.Header().Set("Content-Type", "application/json")
70-
if err := json.NewEncoder(w).Encode(response); err != nil {
71-
zap.L().Error("Failed to encode response",
72-
zap.Error(err),
73-
)
74-
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
75-
return
76-
}
77-
}

internal/services/services.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package services

internal/utils/utils.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ func InitLogger(isProduction bool) {
4242
writeSyncer = zapcore.AddSync(os.Stdout)
4343
}
4444

45-
core := zapcore.NewCore(encoder, writeSyncer, logLevel)
45+
core := zapcore.NewCore(
46+
encoder,
47+
writeSyncer,
48+
logLevel,
49+
)
50+
4651
Log = zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel))
4752

4853
/* allow global logging with zap.L() */

0 commit comments

Comments
 (0)