-
Notifications
You must be signed in to change notification settings - Fork 0
/
auth.go
160 lines (135 loc) · 3.95 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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package auth
import (
"errors"
"flag"
"fmt"
"github.com/dgrijalva/jwt-go"
"io/ioutil"
"net/http"
"time"
)
var (
doAuth = flag.Bool("auth", true, "Turns on authentication")
InvalidToken error = errors.New("invalid-token")
ExpiredToken error = errors.New("token-expired")
ErrNoSignKey = errors.New("no-sign-key")
ErrNoVerifyKey = errors.New("no-verify-key")
)
type UUID string
// Function to override checking of flag. This is useful for testing
// to turn off auth.
type IsAuthOn func() bool
type CheckScope func(string, []string) bool
type SignKey func() []byte
type VerifyKey func() []byte
// Sign keys and verifcation keys are both function of the input which is the http request.
type Settings struct {
TTLHours time.Duration
IsAuthOn IsAuthOn
CheckScope CheckScope
SignKeyFromHttpRequest func(*http.Request) []byte
VerifyKeyFromHttpRequest func(*http.Request) []byte
ErrorRenderer func(http.ResponseWriter, *http.Request, string, int) error
AuthIntercept func(bool, Context) (bool, Context)
}
type HttpHandler func(auth Context, resp http.ResponseWriter, req *http.Request)
type GetScopesFromToken func(*Token) []string
type Service interface {
NewToken() (token *Token)
SignedStringForHttpRequest(token *Token, req *http.Request) (tokenString string, err error)
SignedString(token *Token, f SignKey) (tokenString string, err error)
Parse(tokenString string, f VerifyKey) (token *Token, err error)
ParseForHttpRequest(tokenString string, req *http.Request) (token *Token, err error)
RequiresAuth(scope string, get_scopes GetScopesFromToken, handler HttpHandler) func(http.ResponseWriter, *http.Request)
}
type serviceImpl struct {
settings Settings
GetTime func() time.Time
IsAuthOn IsAuthOn
CheckScope CheckScope
}
type Token struct {
token *jwt.Token
}
func ReadPublicKey(filename string) (key []byte, err error) {
// TODO -- this really isn't doing anything like parsing
// a proper file format like X.509 or anything.
key, err = ioutil.ReadFile(filename)
return
}
func Init(settings Settings) *serviceImpl {
return &serviceImpl{
settings: settings,
GetTime: func() time.Time { return time.Now() },
IsAuthOn: settings.IsAuthOn,
CheckScope: settings.CheckScope,
}
}
func (this *serviceImpl) NewToken() (token *Token) {
token = &Token{token: jwt.New(jwt.GetSigningMethod("HS256"))}
token.SetExpiration(time.Hour * this.settings.TTLHours)
return token
}
func (this *Token) SetExpiration(d time.Duration) {
if d > 0 {
this.token.Claims["exp"] = time.Now().Add(d).Unix()
}
}
func (this *serviceImpl) SignedString(token *Token, f SignKey) (tokenString string, err error) {
if f == nil {
return "", ErrNoSignKey
}
tokenString, err = token.token.SignedString(f())
return
}
func (this *serviceImpl) check_token(t *jwt.Token) (*Token, error) {
if t == nil || !t.Valid {
return nil, InvalidToken
}
// Check expiration if there is one
if expClaim, has := t.Claims["exp"]; has {
exp, ok := expClaim.(float64)
if !ok {
return nil, InvalidToken
}
if this.GetTime().After(time.Unix(int64(exp), 0)) {
return nil, ExpiredToken
}
}
return &Token{token: t}, nil
}
func (this *serviceImpl) Parse(tokenString string, f VerifyKey) (token *Token, err error) {
if f == nil {
return nil, ErrNoVerifyKey
}
t, err := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
return f(), nil
})
if err != nil {
return nil, err
}
return this.check_token(t)
}
func (this *Token) Add(key string, value interface{}) *Token {
this.token.Claims[key] = value
return this
}
func (this *Token) Get(key string) interface{} {
if v, has := this.token.Claims[key]; has {
return v
}
return nil
}
func (this *Token) GetString(key string) string {
if v := this.Get(key); v == nil {
return ""
} else {
return fmt.Sprintf("%s", v)
}
}
func (this *Token) HasKey(key string) bool {
if _, has := this.token.Claims[key]; has {
return true
}
return false
}