-
Notifications
You must be signed in to change notification settings - Fork 204
/
storage_backend.go
146 lines (125 loc) · 3.52 KB
/
storage_backend.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
package backends
import (
"bytes"
"encoding/json"
"github.com/pborman/uuid"
"golang.org/x/crypto/bcrypt"
log "github.com/Sirupsen/logrus"
"github.com/SpectoLabs/hoverfly/core/cache"
)
type User struct {
UUID string `json:"uuid" form:"-"`
Username string `json:"username" form:"username"`
Password string `json:"password" form:"password"`
IsAdmin bool `json:"is_admin" form:"is_admin"`
}
func (u *User) Encode() ([]byte, error) {
buf := new(bytes.Buffer)
enc := json.NewEncoder(buf)
err := enc.Encode(u)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func DecodeUser(user []byte) (*User, error) {
var u *User
buf := bytes.NewBuffer(user)
dec := json.NewDecoder(buf)
err := dec.Decode(&u)
if err != nil {
return nil, err
}
return u, nil
}
// Authentication - generic interface for authentication backend
type Authentication interface {
AddUser(username, password string, admin bool) (err error)
GetUser(username string) (user *User, err error)
GetAllUsers() (users []User, err error)
InvalidateToken(token string) (err error)
IsTokenBlacklisted(token string) (blacklisted bool, err error)
}
// NewCacheBasedAuthBackend - takes two caches - one for token and one for users
func NewCacheBasedAuthBackend(tokenCache, userCache cache.Cache) *CacheAuthBackend {
return &CacheAuthBackend{
TokenCache: tokenCache,
userCache: userCache,
}
}
// UserBucketName - default name for BoltDB bucket that stores user info
const UserBucketName = "authbucket"
// TokenBucketName
const TokenBucketName = "tokenbucket"
// CacheAuthBackend - container to implement Cache instance with i.e. BoltDB backend for storage
type CacheAuthBackend struct {
TokenCache cache.Cache
userCache cache.Cache
}
// AddUser - adds user with provided username, password and admin parameters
func (b *CacheAuthBackend) AddUser(username, password string, admin bool) error {
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 10)
user := User{
UUID: uuid.New(),
Username: username,
Password: string(hashedPassword),
IsAdmin: admin,
}
userBytes, err := user.Encode()
if err != nil {
logUserError(err, username)
return err
}
err = b.userCache.Set([]byte(username), userBytes)
return err
}
func (b *CacheAuthBackend) GetUser(username string) (user *User, err error) {
userBytes, err := b.userCache.Get([]byte(username))
if err != nil {
logUserError(err, username)
return
}
user, err = DecodeUser(userBytes)
if err != nil {
logUserError(err, username)
return
}
return
}
func (b *CacheAuthBackend) InvalidateToken(token string) error {
return b.TokenCache.Set([]byte(token), []byte("whentoexpire"))
}
// IsTokenBlacklisted - checks if token is blacklisted.
func (b *CacheAuthBackend) IsTokenBlacklisted(token string) (bool, error) {
blacklistedToken, err := b.TokenCache.Get([]byte(token))
if err != nil {
log.WithFields(log.Fields{
"error": err,
"token": token,
}).Debug("got error while looking for blacklisted token")
if blacklistedToken != nil {
return true, err
}
return false, err
}
if blacklistedToken == nil {
return false, nil
}
return true, nil
}
func (b *CacheAuthBackend) GetAllUsers() (users []User, err error) {
values, _ := b.userCache.GetAllValues()
users = make([]User, len(values), len(values))
for i, user := range values {
decodedUser, err := DecodeUser(user)
users[i] = *decodedUser
return users, err
}
return users, err
}
func logUserError(err error, username string) {
log.WithFields(log.Fields{
"error": err.Error(),
"username": username,
})
}