forked from shaj13/go-guardian
-
Notifications
You must be signed in to change notification settings - Fork 0
/
static.go
137 lines (110 loc) · 3.11 KB
/
static.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
package token
import (
"context"
"encoding/csv"
"fmt"
"io"
"net/http"
"os"
"strings"
"sync"
"github.com/m87carlson/go-guardian/v2/auth"
)
// NewStaticFromFile returns static auth.Strategy, populated from a CSV file.
// The CSV file must contain records in one of following formats
// basic record: `token,username,userid`
// intermediate record: `token,username,userid,"group1,group2"`
// full record: `token,username,userid,"group1,group2","extension=1,example=2"`
func NewStaticFromFile(path string, opts ...auth.Option) (auth.Strategy, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
tokens := make(map[string]auth.Info)
reader := csv.NewReader(file)
reader.FieldsPerRecord = -1
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
return nil, err
}
if len(record) < 3 {
return nil, fmt.Errorf(
"strategies/token: record must have at least 3 columns (token, username, id), Record: %v",
record,
)
}
if record[0] == "" {
return nil, fmt.Errorf("strategies/token: a non empty token is required, Record: %v", record)
}
// if token Contains Bearer remove it
record[0] = strings.TrimPrefix(record[0], "Bearer ")
if _, ok := tokens[record[0]]; ok {
return nil, fmt.Errorf("strategies/token: token already exists, Record: %v", record)
}
info := auth.NewUserInfo(record[1], record[2], nil, nil)
if len(record) >= 4 {
info.SetGroups(strings.Split(record[3], ","))
}
if len(record) >= 5 {
extsSlice := strings.Split(record[4], ",")
exts := make(map[string][]string)
for _, v := range extsSlice {
if strings.Contains(v, "=") {
ext := strings.Split(v, "=")
exts[ext[0]] = []string{ext[1]}
}
}
info.SetExtensions(exts)
}
tokens[record[0]] = info
}
return NewStatic(tokens, opts...), nil
}
// NewStatic returns static auth.Strategy, populated from a map.
func NewStatic(tokens map[string]auth.Info, opts ...auth.Option) auth.Strategy {
s := &static{
tokens: make(map[string]auth.Info, len(tokens)),
mu: new(sync.Mutex),
}
c := newCore(s, opts...)
for k, v := range tokens {
_ = c.Append(k, v)
}
return c
}
// Static implements strategy and define a synchronized map honor all predefined bearer tokens.
type static struct {
mu *sync.Mutex
tokens map[string]auth.Info
}
// authenticate user request against predefined tokens by verifying request token existence in the static Map.
// Once token found auth.Info returned with a nil error,
// Otherwise, a nil auth.Info and ErrTokenNotFound returned.
func (s *static) authenticate(ctx context.Context, r *http.Request, hash, _ string) (auth.Info, error) {
s.mu.Lock()
defer s.mu.Unlock()
info, ok := s.tokens[hash]
if !ok {
return nil, ErrTokenNotFound
}
return info, nil
}
// Append add new token to static store.
func (s *static) append(token string, info auth.Info) error {
s.mu.Lock()
defer s.mu.Unlock()
s.tokens[token] = info
return nil
}
// Revoke delete token from static store.
func (s *static) revoke(token string) error {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.tokens, token)
return nil
}