-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmiddleware.go
79 lines (67 loc) · 2.65 KB
/
middleware.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package authutils
import (
"context"
"net/http"
"github.com/gin-gonic/gin"
"github.com/savannahghi/serverutils"
)
// authCheckFn is a function type for authorization and authentication checks
// there can be several e.g an authentication check runs first then an authorization
// check runs next if the authentication passes etc
type authCheckFn = func(
ctx context.Context,
r *http.Request,
) (bool, map[string]string, *TokenIntrospectionResponse)
// SladeAuthenticationMiddleware is responsible for validating user's authentication credentials before allowing access to protected routes.
// It uses the provided authentication service to check the user's token
// and ensure it is valid and has the necessary permissions for the requested resource
func SladeAuthenticationMiddleware(c Client) func(http.Handler) http.Handler {
// multiple checks will be run in sequence (order matters)
// the first check to succeed will call `c.Next()` and `return`
// this means that more permissive checks (e.g exceptions) should come first
checkFuncs := []authCheckFn{c.HasValidSlade360BearerToken}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
errs := []map[string]string{}
// in case authorization does not succeed, accumulated errors
// are returned to the client
for _, checkFunc := range checkFuncs {
shouldContinue, errMap, authToken := checkFunc(r.Context(), r)
if shouldContinue {
// put the auth token in the context
ctx := context.WithValue(r.Context(), AuthTokenContextKey, authToken)
// and call the next with our new context
r = r.WithContext(ctx)
next.ServeHTTP(w, r)
return
}
errs = append(errs, errMap)
}
// if we got here, it is because we have errors.
// write an error response)
serverutils.WriteJSONResponse(w, errs, http.StatusUnauthorized)
},
)
}
}
// SladeAuthenticationGinMiddleware is an authentication middleware for servers using Gin. It checks the user token and ensures
// that it is valid
func SladeAuthenticationGinMiddleware(cl Client) gin.HandlerFunc {
checkFuncs := []authCheckFn{cl.HasValidSlade360BearerToken}
return func(c *gin.Context) {
errs := []map[string]string{}
for _, checkFunc := range checkFuncs {
shouldContinue, errMap, authToken := checkFunc(c.Request.Context(), c.Request)
if shouldContinue {
ctx := context.WithValue(c.Request.Context(), AuthTokenContextKey, authToken)
c.Request = c.Request.WithContext(ctx)
c.Next()
return
}
errs = append(errs, errMap)
}
serverutils.WriteJSONResponse(c.Writer, errs, http.StatusUnauthorized)
c.Abort()
}
}