...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package authgroup
16
17 import (
18 "context"
19 "net/http"
20
21 "github.com/go-kivik/kivik/v4"
22 internal "github.com/go-kivik/kivik/v4/int/errors"
23 "github.com/go-kivik/kivik/v4/x/kivikd/authdb"
24 )
25
26
27 type AuthGroup []authdb.UserStore
28
29 var _ authdb.UserStore = AuthGroup{}
30
31
32
33 func New(userStores ...authdb.UserStore) authdb.UserStore {
34 return append(AuthGroup{}, userStores...)
35 }
36
37 func (g AuthGroup) loop(ctx context.Context, fn func(authdb.UserStore) (*authdb.UserContext, error)) (*authdb.UserContext, error) {
38 var firstErr error
39 for _, store := range g {
40 uCtx, err := fn(store)
41 if err == nil {
42 return uCtx, nil
43 }
44 if kivik.HTTPStatus(err) != http.StatusNotFound && firstErr == nil {
45 firstErr = err
46 }
47 select {
48
49 case <-ctx.Done():
50 return nil, ctx.Err()
51 default:
52 }
53 }
54 if firstErr == nil {
55 return nil, &internal.Error{Status: http.StatusNotFound, Message: "user not found"}
56 }
57 return nil, firstErr
58 }
59
60
61
62
63
64
65 func (g AuthGroup) Validate(ctx context.Context, username, password string) (*authdb.UserContext, error) {
66 return g.loop(ctx, func(store authdb.UserStore) (*authdb.UserContext, error) {
67 return store.Validate(ctx, username, password)
68 })
69 }
70
71
72
73
74
75
76 func (g AuthGroup) UserCtx(ctx context.Context, username string) (*authdb.UserContext, error) {
77 return g.loop(ctx, func(store authdb.UserStore) (*authdb.UserContext, error) {
78 return store.UserCtx(ctx, username)
79 })
80 }
81
View as plain text