-
Notifications
You must be signed in to change notification settings - Fork 0
/
auth.go
142 lines (123 loc) · 3.84 KB
/
auth.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"context"
"net/http"
"time"
"github.com/golang-jwt/jwt/v4"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"golang.org/x/crypto/bcrypt"
)
// Claim describes the structure of a JWT claim (this is the same payload as in the
// https://github.com/a-shine/api-gateway repo which is what makes them compatible)
type Claim struct {
Id string `json:"id"`
Groups []string `json:"groups"`
jwt.RegisteredClaims
}
// verifyPassword compares a hashed password with the raw password
func verifyPassword(hashedPwd string, plainPwd string) bool {
byteHash := []byte(hashedPwd)
err := bcrypt.CompareHashAndPassword(byteHash, []byte(plainPwd))
return err == nil // true if the err is nil and false otherwise
}
func processClaim(token string) (int, *Claim) {
claim := &Claim{}
// c, err := r.Cookie("token")
// if err != nil {
// if err == http.ErrNoCookie {
// return http.StatusUnauthorized, nil
// }
// return http.StatusBadRequest, nil
// }
// tknStr := c.Value
tkn, err := jwt.ParseWithClaims(token, claim, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
if err != nil {
if err == jwt.ErrSignatureInvalid {
return http.StatusUnauthorized, nil
}
return http.StatusBadRequest, nil
}
if !tkn.Valid {
return http.StatusUnauthorized, nil
}
return http.StatusOK, claim
}
func authenticate(users *mongo.Collection, claim *Claim) (int, *Client) {
user := &Client{}
// Get user by the ID in the token claim payload
objID, _ := primitive.ObjectIDFromHex(claim.Id)
value := users.FindOne(context.Background(), bson.M{"_id": objID}).Decode(user)
// Check user if user can be authenticated
if value == mongo.ErrNoDocuments {
return http.StatusUnauthorized, user
} else {
return http.StatusOK, user
}
}
func authAndAuthorised(users *mongo.Collection, claim *Claim) (int, *Client) {
code, user := authenticate(users, claim)
switch code {
case http.StatusOK:
if user.Suspended {
return http.StatusUnauthorized, nil
} else {
return http.StatusOK, user
}
default:
return code, nil
}
}
func authAndAuthorisedAdmin(users *mongo.Collection, claim *Claim) (int, *Client) {
code, user := authAndAuthorised(users, claim)
switch code {
case http.StatusOK:
// If user group contains "admin" then they are authorised
for _, group := range user.Groups {
if group == "admin" {
return http.StatusOK, user
}
}
return http.StatusUnauthorized, nil
default:
return code, nil
}
}
// Needs to be a jwt token so that the API gateway can verify it
func generateAPIClientToken(client *Client) (string, error) {
// Create the JWT claims, which includes the user ID with no expiration time
claims := &Claim{
Id: client.Id.Hex(),
Groups: client.Groups,
RegisteredClaims: jwt.RegisteredClaims{},
}
// Create the JWT token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenStr, err := token.SignedString(jwtKey)
return tokenStr, err
}
func genToken(id string, groups []string) (string, error) {
// Declare the expiration time of the token as determined by the jwtTokenExpiration variable
expirationTime := time.Now().Add(jwtTokenExpiration)
// Create the JWT claims, which includes the authenticated user ID and expiry time
claims := &Claim{
Id: id,
Groups: groups,
RegisteredClaims: jwt.RegisteredClaims{
// In JWT, the expiry time is expressed as unix milliseconds
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
// Create the token with the HS256 algorithm used for signing, and the created claim
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// Create the JWT string
tokenString, err := token.SignedString(jwtKey)
if err != nil {
// If there is an error in creating the JWT return an internal server error
return "", err
}
return tokenString, nil
}