Blame view
auth_utility.go
5.04 KB
ea858b8a7 refactoring |
1 |
package webutility |
90fd36e9b resolved some dep... |
2 3 |
import ( |
90fd36e9b resolved some dep... |
4 |
"errors" |
90fd36e9b resolved some dep... |
5 6 7 8 9 |
"time" "crypto/sha256" "crypto/rand" "encoding/hex" "strings" |
33d137a67 Functional role c... |
10 |
"net/http" |
90fd36e9b resolved some dep... |
11 |
"github.com/dgrijalva/jwt-go" |
33d137a67 Functional role c... |
12 |
"fmt" |
90fd36e9b resolved some dep... |
13 |
) |
7d3deb50d modified list_con... |
14 15 |
const OneDay = time.Hour*24 const OneWeek = OneDay*7 |
90fd36e9b resolved some dep... |
16 17 18 |
const saltSize = 32 const appName = "korisnicki-centar" const secret = "korisnicki-centar-api" |
33d137a67 Functional role c... |
19 20 21 22 |
const RoleAdmin string = "ADMINISTRATOR" const RoleManager string = "RUKOVODILAC" const RoleReporter string = "REPORTER" const RoleOperator string = "OPERATER" |
6ec91280b working on docume... |
23 |
// TokenClaims are JWT token claims. |
90fd36e9b resolved some dep... |
24 25 |
type TokenClaims struct { Username string `json:"username"` |
7d3deb50d modified list_con... |
26 |
Role string `json:"role"` |
90fd36e9b resolved some dep... |
27 28 |
jwt.StandardClaims } |
6ec91280b working on docume... |
29 |
// CredentialsStruct is an instace of username/password values. |
90fd36e9b resolved some dep... |
30 31 32 33 |
type CredentialsStruct struct { Username string `json:"username"` Password string `json:"password"` } |
6ec91280b working on docume... |
34 |
// generateSalt returns a string of random characters of 'saltSize' length. |
4b4ea384f hmm |
35 |
func generateSalt() (salt string, err error) { |
90fd36e9b resolved some dep... |
36 |
rawsalt := make([]byte, saltSize) |
33fd58161 minor changes, sh... |
37 |
|
4b4ea384f hmm |
38 |
_, err = rand.Read(rawsalt) |
90fd36e9b resolved some dep... |
39 40 41 |
if err != nil { return "", err } |
33fd58161 minor changes, sh... |
42 |
|
90fd36e9b resolved some dep... |
43 44 45 |
salt = hex.EncodeToString(rawsalt) return salt, nil } |
e1fbb41f9 added comments |
46 47 |
// HashString hashes input string with SHA256 algorithm. // If the presalt parameter is not provided HashString will generate new salt string. |
6ec91280b working on docume... |
48 |
// Returns hash and salt string or an error if it fails. |
33fd58161 minor changes, sh... |
49 |
func HashString(str string, presalt string) (hash, salt string, err error) { |
90fd36e9b resolved some dep... |
50 51 |
// chech if message is presalted if presalt == "" { |
33fd58161 minor changes, sh... |
52 |
salt, err = generateSalt() |
90fd36e9b resolved some dep... |
53 54 55 56 57 58 59 60 |
if err != nil { return "", "", err } } else { salt = presalt } // convert strings to raw byte slices |
33fd58161 minor changes, sh... |
61 |
rawstr := []byte(str) |
90fd36e9b resolved some dep... |
62 63 64 65 |
rawsalt, err := hex.DecodeString(salt) if err != nil { return "", "", err } |
33fd58161 minor changes, sh... |
66 67 68 |
rawdata := make([]byte, len(rawstr) + len(rawsalt)) rawdata = append(rawdata, rawstr...) |
90fd36e9b resolved some dep... |
69 70 71 72 73 74 |
rawdata = append(rawdata, rawsalt...) // hash message + salt hasher := sha256.New() hasher.Write(rawdata) rawhash := hasher.Sum(nil) |
33fd58161 minor changes, sh... |
75 |
|
90fd36e9b resolved some dep... |
76 77 78 |
hash = hex.EncodeToString(rawhash) return hash, salt, nil } |
6ec91280b working on docume... |
79 80 |
// CreateAPIToken returns JWT token with encoded username, role, expiration date and issuer claims. // It returns an error if it fails. |
33fd58161 minor changes, sh... |
81 |
func CreateAPIToken(username, role string) (string, error) { |
7d3deb50d modified list_con... |
82 |
var apiToken string |
90fd36e9b resolved some dep... |
83 84 85 |
var err error if err != nil { |
6f4b8a711 token response ch... |
86 |
return "", err |
90fd36e9b resolved some dep... |
87 88 89 90 91 92 93 94 95 96 97 98 |
} claims := TokenClaims{ username, role, jwt.StandardClaims{ ExpiresAt: (time.Now().Add(OneWeek)).Unix(), Issuer: appName, }, } jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
6f4b8a711 token response ch... |
99 |
apiToken, err = jwtToken.SignedString([]byte(secret)) |
90fd36e9b resolved some dep... |
100 |
if err != nil { |
6f4b8a711 token response ch... |
101 |
return "", err |
90fd36e9b resolved some dep... |
102 103 104 |
} return apiToken, nil } |
6ec91280b working on docume... |
105 106 |
// RefreshAPIToken prolongs JWT token's expiration date for one week. // It returns new JWT token or an error if it fails. |
6f4b8a711 token response ch... |
107 |
func RefreshAPIToken(tokenString string) (string, error) { |
7d3deb50d modified list_con... |
108 |
var newToken string |
90fd36e9b resolved some dep... |
109 |
tokenString = strings.TrimPrefix(tokenString, "Bearer ") |
e1fbb41f9 added comments |
110 |
token, err := jwt.ParseWithClaims(tokenString, &TokenClaims{}, secretFunc) |
90fd36e9b resolved some dep... |
111 |
if err != nil { |
6f4b8a711 token response ch... |
112 |
return "", err |
90fd36e9b resolved some dep... |
113 114 115 116 117 |
} // type assertion claims, ok := token.Claims.(*TokenClaims) if !ok || !token.Valid { |
6f4b8a711 token response ch... |
118 |
return "", errors.New("token is not valid") |
90fd36e9b resolved some dep... |
119 120 121 122 |
} claims.ExpiresAt = (time.Now().Add(OneWeek)).Unix() jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
6f4b8a711 token response ch... |
123 |
newToken, err = jwtToken.SignedString([]byte(secret)) |
90fd36e9b resolved some dep... |
124 |
if err != nil { |
6f4b8a711 token response ch... |
125 |
return "", err |
90fd36e9b resolved some dep... |
126 127 128 129 |
} return newToken, nil } |
e1fbb41f9 added comments |
130 |
// ParseAPIToken parses JWT token claims. |
6ec91280b working on docume... |
131 |
// It returns a pointer to TokenClaims struct or an error if it fails. |
b291ac8c4 clened up |
132 |
func ParseAPIToken(tokenString string) (*TokenClaims, error) { |
e1fbb41f9 added comments |
133 |
if ok := strings.HasPrefix(tokenString, "Bearer "); ok { |
90fd36e9b resolved some dep... |
134 135 136 137 |
tokenString = strings.TrimPrefix(tokenString, "Bearer ") } else { return &TokenClaims{}, errors.New("Authorization header is incomplete") } |
e1fbb41f9 added comments |
138 |
token, err := jwt.ParseWithClaims(tokenString, &TokenClaims{}, secretFunc) |
90fd36e9b resolved some dep... |
139 140 141 142 143 144 145 146 147 148 149 |
if err != nil { return &TokenClaims{}, err } // type assertion claims, ok := token.Claims.(*TokenClaims) if !ok || !token.Valid { return &TokenClaims{}, errors.New("token is not valid") } return claims, nil } |
33d137a67 Functional role c... |
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
func GetTokenClaims(r *http.Request) (claims *TokenClaims, err error) { token := r.Header.Get("Authorization") if ok := strings.HasPrefix(token, "Bearer "); ok { token = strings.TrimPrefix(token, "Bearer ") } else { return &TokenClaims{}, errors.New("Authorization header is incomplete") } parsedToken, err := jwt.ParseWithClaims(token, &TokenClaims{}, secretFunc) if err != nil { return &TokenClaims{}, err } // type assertion claims, ok := parsedToken.Claims.(*TokenClaims) if !ok || !parsedToken.Valid { return &TokenClaims{}, errors.New("token is not valid") } return claims, err } |
6ec91280b working on docume... |
170 |
// secretFunc returns byte slice of API secret keyword. |
e1fbb41f9 added comments |
171 172 |
func secretFunc(token *jwt.Token) (interface{}, error) { return []byte(secret), nil |
90fd36e9b resolved some dep... |
173 |
} |
33d137a67 Functional role c... |
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
// roleAuthorized returns true if role from userClaims matches any of the authorizedRoles // or if authorizedRoles contains "*". func roleAuthorized(authorizedRoles []string, userClaims *TokenClaims) bool { if userClaims == nil { return false } for _, r := range authorizedRoles { fmt.Printf("comparing %s with %s ", userClaims.Role, r) if userClaims.Role == r || r == "*" { return true } } return false } |