forked from shaj13/go-guardian
/
cached.go
70 lines (56 loc) · 1.87 KB
/
cached.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
package basic
import (
"context"
"net/http"
"github.com/Sosivio/go-guardian/v2/auth"
"github.com/Sosivio/go-guardian/v2/auth/internal"
)
// ExtensionKey represents a key for the password in info extensions.
// Typically used when basic strategy cache the authentication decisions.
const ExtensionKey = "x-go-guardian-basic-password"
// NewCached return new auth.Strategy.
// The returned strategy, caches the invocation result of authenticate function.
func NewCached(f AuthenticateFunc, cache auth.Cache, opts ...auth.Option) auth.Strategy {
cb := new(cachedBasic)
cb.fn = f
cb.cache = cache
cb.comparator = plainText{}
cb.hasher = internal.PlainTextHasher{}
for _, opt := range opts {
opt.Apply(cb)
}
return New(cb.authenticate, opts...)
}
type cachedBasic struct {
fn AuthenticateFunc
comparator Comparator
cache auth.Cache
hasher internal.Hasher
}
func (c *cachedBasic) authenticate(ctx context.Context, r *http.Request, userName, pass string) (auth.Info, error) { // nolint:lll
hash := c.hasher.Hash(userName)
v, ok := c.cache.Load(hash)
// if info not found invoke user authenticate function
if !ok {
return c.authenticatAndHash(ctx, r, hash, userName, pass)
}
if _, ok := v.(auth.Info); !ok {
return nil, auth.NewTypeError("strategies/basic:", (*auth.Info)(nil), v)
}
info := v.(auth.Info)
ext := info.GetExtensions()
if !ext.Has(ExtensionKey) {
return c.authenticatAndHash(ctx, r, hash, userName, pass)
}
return info, c.comparator.Compare(ext.Get(ExtensionKey), pass)
}
func (c *cachedBasic) authenticatAndHash(ctx context.Context, r *http.Request, hash string, userName, pass string) (auth.Info, error) { //nolint:lll
info, err := c.fn(ctx, r, userName, pass)
if err != nil {
return nil, err
}
hashedPass, _ := c.comparator.Hash(pass)
info.GetExtensions().Set(ExtensionKey, hashedPass)
c.cache.Store(hash, info)
return info, nil
}