Blame view
auth.go
5.65 KB
ea858b8a7 refactoring |
1 |
package webutility |
90fd36e9b resolved some dep... |
2 3 |
import ( |
90fd36e9b resolved some dep... |
4 |
"crypto/rand" |
d2ddf82ef started on new rbac |
5 |
"crypto/sha256" |
90fd36e9b resolved some dep... |
6 |
"encoding/hex" |
d2ddf82ef started on new rbac |
7 |
"errors" |
33d137a67 Functional role c... |
8 |
"net/http" |
d2ddf82ef started on new rbac |
9 10 |
"strings" "time" |
33d137a67 Functional role c... |
11 |
|
90fd36e9b resolved some dep... |
12 |
"github.com/dgrijalva/jwt-go" |
90fd36e9b resolved some dep... |
13 |
) |
fbf92700f renamed package v... |
14 15 |
var _issuer = "webutility" var _secret = "webutility" |
90fd36e9b resolved some dep... |
16 |
|
6ec91280b working on docume... |
17 |
// TokenClaims are JWT token claims. |
90fd36e9b resolved some dep... |
18 |
type TokenClaims struct { |
a205e8f40 changes |
19 20 21 22 |
// extending a struct jwt.StandardClaims // custom claims |
6620591d8 moved DeliverPayl... |
23 24 25 |
Token string `json:"access_token"` TokenType string `json:"token_type"` Username string `json:"username"` |
de25e1deb removed redundant... |
26 |
RoleName string `json:"role"` |
a205e8f40 changes |
27 |
RoleID int64 `json:"role_id"` |
6620591d8 moved DeliverPayl... |
28 |
ExpiresIn int64 `json:"expires_in"` |
90fd36e9b resolved some dep... |
29 |
} |
707782344 lint; vet |
30 |
// InitJWT ... |
fbf92700f renamed package v... |
31 32 33 |
func InitJWT(issuer, secret string) { _issuer = issuer _secret = secret |
f84e7607d added dictionary;... |
34 |
} |
0feac5059 renamed ValidateC... |
35 36 |
// ValidateHash hashes pass and salt and returns comparison result with resultHash func ValidateHash(pass, salt, resultHash string) (bool, error) { |
bc3671b26 refactoring token... |
37 |
hash, _, err := CreateHash(pass, salt) |
90fd36e9b resolved some dep... |
38 |
if err != nil { |
f84e7607d added dictionary;... |
39 |
return false, err |
90fd36e9b resolved some dep... |
40 |
} |
f84e7607d added dictionary;... |
41 42 |
res := hash == resultHash return res, nil |
90fd36e9b resolved some dep... |
43 |
} |
bc3671b26 refactoring token... |
44 45 46 47 |
// CreateHash hashes str using SHA256. // If the presalt parameter is not provided CreateHash will generate new salt string. // Returns hash and salt strings or an error if it fails. func CreateHash(str, presalt string) (hash, salt string, err error) { |
90fd36e9b resolved some dep... |
48 49 |
// chech if message is presalted if presalt == "" { |
bc3671b26 refactoring token... |
50 |
salt, err = randomSalt() |
90fd36e9b resolved some dep... |
51 52 53 54 55 56 57 58 |
if err != nil { return "", "", err } } else { salt = presalt } // convert strings to raw byte slices |
33fd58161 minor changes, sh... |
59 |
rawstr := []byte(str) |
90fd36e9b resolved some dep... |
60 61 62 63 |
rawsalt, err := hex.DecodeString(salt) if err != nil { return "", "", err } |
33fd58161 minor changes, sh... |
64 |
|
d2ddf82ef started on new rbac |
65 |
rawdata := make([]byte, len(rawstr)+len(rawsalt)) |
33fd58161 minor changes, sh... |
66 |
rawdata = append(rawdata, rawstr...) |
90fd36e9b resolved some dep... |
67 68 69 70 71 72 |
rawdata = append(rawdata, rawsalt...) // hash message + salt hasher := sha256.New() hasher.Write(rawdata) rawhash := hasher.Sum(nil) |
33fd58161 minor changes, sh... |
73 |
|
90fd36e9b resolved some dep... |
74 75 76 |
hash = hex.EncodeToString(rawhash) return hash, salt, nil } |
bc3671b26 refactoring token... |
77 |
// CreateAuthToken returns JWT token with encoded username, role, expiration date and issuer claims. |
6ec91280b working on docume... |
78 |
// It returns an error if it fails. |
de25e1deb removed redundant... |
79 |
func CreateAuthToken(username string, roleName string, roleID int64) (TokenClaims, error) { |
bc3671b26 refactoring token... |
80 |
t0 := (time.Now()).Unix() |
3fffcb954 removed old http API |
81 |
t1 := (time.Now().Add(time.Hour * 24 * 7)).Unix() |
90fd36e9b resolved some dep... |
82 |
claims := TokenClaims{ |
bc3671b26 refactoring token... |
83 84 |
TokenType: "Bearer", Username: username, |
de25e1deb removed redundant... |
85 86 |
RoleName: roleName, RoleID: roleID, |
bc3671b26 refactoring token... |
87 |
ExpiresIn: t1 - t0, |
90fd36e9b resolved some dep... |
88 |
} |
bc3671b26 refactoring token... |
89 90 91 |
// initialize jwt.StandardClaims fields (anonymous struct) claims.IssuedAt = t0 claims.ExpiresAt = t1 |
fbf92700f renamed package v... |
92 |
claims.Issuer = _issuer |
90fd36e9b resolved some dep... |
93 94 |
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
fbf92700f renamed package v... |
95 |
token, err := jwtToken.SignedString([]byte(_secret)) |
90fd36e9b resolved some dep... |
96 |
if err != nil { |
bc3671b26 refactoring token... |
97 |
return TokenClaims{}, err |
90fd36e9b resolved some dep... |
98 |
} |
bc3671b26 refactoring token... |
99 100 |
claims.Token = token return claims, nil |
90fd36e9b resolved some dep... |
101 |
} |
3fffcb954 removed old http API |
102 103 |
// RefreshAuthToken returns new JWT token with same claims contained in tok but with prolonged expiration date. // It returns an error if it fails. |
c7aadbb39 minor changes |
104 105 |
func RefreshAuthToken(tok string) (TokenClaims, error) { token, err := jwt.ParseWithClaims(tok, &TokenClaims{}, secretFunc) |
90fd36e9b resolved some dep... |
106 |
if err != nil { |
052f8a3a6 token validation ... |
107 |
if validation, ok := err.(*jwt.ValidationError); ok { |
6faf94f85 Fixed auth check ... |
108 |
// don't return error if token is expired, just extend it |
052f8a3a6 token validation ... |
109 110 111 112 113 114 |
if !(validation.Errors&jwt.ValidationErrorExpired != 0) { return TokenClaims{}, err } } else { return TokenClaims{}, err } |
90fd36e9b resolved some dep... |
115 116 117 118 |
} // type assertion claims, ok := token.Claims.(*TokenClaims) |
052f8a3a6 token validation ... |
119 |
if !ok { |
bc3671b26 refactoring token... |
120 |
return TokenClaims{}, errors.New("token is not valid") |
90fd36e9b resolved some dep... |
121 |
} |
bc3671b26 refactoring token... |
122 |
// extend token expiration date |
de25e1deb removed redundant... |
123 |
return CreateAuthToken(claims.Username, claims.RoleName, claims.RoleID) |
90fd36e9b resolved some dep... |
124 |
} |
707782344 lint; vet |
125 |
// AuthCheck ... |
3f8e3c437 minor changes |
126 |
func AuthCheck(req *http.Request, roles string) (*TokenClaims, error) { |
d29773cc4 ProcessRBAC |
127 128 129 |
// validate token and check expiration date claims, err := GetTokenClaims(req) if err != nil { |
3f8e3c437 minor changes |
130 131 132 133 134 |
return claims, err } if roles == "" { return claims, nil |
d29773cc4 ProcessRBAC |
135 |
} |
3f8e3c437 minor changes |
136 |
|
d29773cc4 ProcessRBAC |
137 138 |
// check if token has expired if claims.ExpiresAt < (time.Now()).Unix() { |
3f8e3c437 minor changes |
139 |
return claims, errors.New("token has expired") |
d29773cc4 ProcessRBAC |
140 |
} |
3fffcb954 removed old http API |
141 |
if roles == "*" { |
3f8e3c437 minor changes |
142 |
return claims, nil |
3fffcb954 removed old http API |
143 144 145 |
} parts := strings.Split(roles, ",") |
707782344 lint; vet |
146 |
for i := range parts { |
3fffcb954 removed old http API |
147 |
r := strings.Trim(parts[i], " ") |
de25e1deb removed redundant... |
148 |
if claims.RoleName == r { |
3f8e3c437 minor changes |
149 |
return claims, nil |
d29773cc4 ProcessRBAC |
150 151 |
} } |
6faf94f85 Fixed auth check ... |
152 |
return claims, errors.New("unauthorized role access") |
d29773cc4 ProcessRBAC |
153 |
} |
3fffcb954 removed old http API |
154 |
// GetTokenClaims extracts JWT claims from Authorization header of req. |
bc3671b26 refactoring token... |
155 156 157 158 159 160 |
// Returns token claims or an error. func GetTokenClaims(req *http.Request) (*TokenClaims, error) { // check for and strip 'Bearer' prefix var tokstr string authHead := req.Header.Get("Authorization") if ok := strings.HasPrefix(authHead, "Bearer "); ok { |
2d79a4120 Responses contain... |
161 |
tokstr = strings.TrimPrefix(authHead, "Bearer ") |
33d137a67 Functional role c... |
162 |
} else { |
65d214f47 improved middlewa... |
163 |
return &TokenClaims{}, errors.New("authorization header is incomplete") |
33d137a67 Functional role c... |
164 |
} |
bc3671b26 refactoring token... |
165 |
token, err := jwt.ParseWithClaims(tokstr, &TokenClaims{}, secretFunc) |
33d137a67 Functional role c... |
166 167 168 169 170 |
if err != nil { return &TokenClaims{}, err } // type assertion |
bc3671b26 refactoring token... |
171 172 |
claims, ok := token.Claims.(*TokenClaims) if !ok || !token.Valid { |
33d137a67 Functional role c... |
173 174 |
return &TokenClaims{}, errors.New("token is not valid") } |
33d137a67 Functional role c... |
175 |
|
bc3671b26 refactoring token... |
176 |
return claims, nil |
90fd36e9b resolved some dep... |
177 |
} |
33d137a67 Functional role c... |
178 |
|
984b5e55a DecodeJWT |
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
func DecodeJWT(secret, token string) (*TokenClaims, error) { secretfunc := func(*jwt.Token) (interface{}, error) { return []byte(secret), nil } tok, err := jwt.ParseWithClaims(token, &TokenClaims{}, secretfunc) if err != nil { if validation, ok := err.(*jwt.ValidationError); ok { // don't return error if token is expired if !(validation.Errors&jwt.ValidationErrorExpired != 0) { return nil, err } } else { return nil, err } } // type assertion claims, ok := tok.Claims.(*TokenClaims) if !ok { return &TokenClaims{}, errors.New("token is not valid") } return claims, nil } |
3fffcb954 removed old http API |
204 |
// randomSalt returns a string of 32 random characters. |
bc3671b26 refactoring token... |
205 |
func randomSalt() (s string, err error) { |
368c7f87b pagination work |
206 |
const saltSize = 32 |
bc3671b26 refactoring token... |
207 |
rawsalt := make([]byte, saltSize) |
d2ddf82ef started on new rbac |
208 |
|
bc3671b26 refactoring token... |
209 |
_, err = rand.Read(rawsalt) |
d2ddf82ef started on new rbac |
210 |
if err != nil { |
bc3671b26 refactoring token... |
211 |
return "", err |
33d137a67 Functional role c... |
212 |
} |
d2ddf82ef started on new rbac |
213 |
|
bc3671b26 refactoring token... |
214 215 |
s = hex.EncodeToString(rawsalt) return s, nil |
33d137a67 Functional role c... |
216 |
} |
d2ddf82ef started on new rbac |
217 |
|
bc3671b26 refactoring token... |
218 219 |
// secretFunc returns byte slice of API secret keyword. func secretFunc(token *jwt.Token) (interface{}, error) { |
fbf92700f renamed package v... |
220 |
return []byte(_secret), nil |
d2ddf82ef started on new rbac |
221 |
} |