-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauthz.go
107 lines (96 loc) · 2.09 KB
/
authz.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
package main
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
"time"
"crypto/hmac"
"crypto/sha512"
)
const tokenDuration = time.Hour * 24 * 30
var HMACKey []byte = make([]byte, 128)
func init() {
n, err := rand.Read(HMACKey)
if err != nil {
panic(err)
}
if n != 128 {
panic("bad entropy")
}
}
type authToken struct {
Issued time.Time
Expires time.Time
Username string
}
func checkHMACSHA512(tokData, hmacResult1 []byte) bool {
hmacResult2 := hmacSHA512(tokData)
return subtle.ConstantTimeCompare(hmacResult1, hmacResult2) == 1
}
func hmacSHA512(tokData []byte) []byte {
hmacResult := hmac.New(sha512.New, HMACKey)
_, err := hmacResult.Write(tokData)
if err != nil {
panic(err)
}
return hmacResult.Sum(nil)
}
func issueToken(username string) (string, time.Time) {
now := time.Now()
expires := now.Add(tokenDuration)
tokData, err := json.Marshal(authToken{
Issued: now,
Expires: expires,
Username: username,
})
if err != nil {
panic(err)
}
hmacResult := hmacSHA512(tokData)
cookieValue := fmt.Sprintf("%s.%s",
base64.StdEncoding.EncodeToString(tokData),
base64.StdEncoding.EncodeToString(hmacResult),
)
return cookieValue, expires
}
var expiredToken error = errors.New("Token expired")
func authz(cookie, hostname string, u *url.URL) (string, error) {
failedAuth := errors.New("Failed to authorize")
sc := strings.Split(cookie, ".")
if len(sc) != 2 {
return "", failedAuth
}
tokData, err := base64.StdEncoding.DecodeString(sc[0])
if err != nil {
return "", failedAuth
}
hmacResult, err := base64.StdEncoding.DecodeString(sc[1])
if err != nil {
return "", failedAuth
}
if !checkHMACSHA512(tokData, hmacResult) {
return "", failedAuth
}
var tok authToken
err = json.Unmarshal(tokData, &tok)
if err != nil {
panic(err)
}
now := time.Now()
if tok.Expires.Before(now) {
return "", expiredToken
}
entry, ok := fsUserEntries.Lookup(tok.Username)
if !ok {
return "", failedAuth
}
if tok.Issued.Before(entry.TokenCutoff) {
return "", expiredToken
}
return tok.Username, nil
}