...
1
2
3
4
5
6
7
8
9
10
11
12
13 package chttp
14
15 import (
16 "crypto/hmac"
17 "crypto/sha1"
18 "encoding/hex"
19 "fmt"
20 "net/http"
21 "strings"
22
23 "github.com/go-kivik/kivik/v4"
24 )
25
26 type proxyAuth struct {
27 Username string
28 Secret string
29 Roles []string
30 Headers http.Header
31
32 transport http.RoundTripper
33 token string
34 }
35
36 var (
37 _ authenticator = &proxyAuth{}
38 _ kivik.Option = (*proxyAuth)(nil)
39 )
40
41 func (a *proxyAuth) Apply(target interface{}) {
42 if auth, ok := target.(*authenticator); ok {
43
44
45 *auth = &proxyAuth{
46 Username: a.Username,
47 Secret: a.Secret,
48 Roles: a.Roles,
49 Headers: a.Headers,
50 }
51 }
52 }
53
54 func (a *proxyAuth) String() string {
55 return fmt.Sprintf("[ProxyAuth{username:%s,secret:%s}]", a.Username, strings.Repeat("*", len(a.Secret)))
56 }
57
58 func (a *proxyAuth) header(header string) string {
59 if h := a.Headers.Get(header); h != "" {
60 return http.CanonicalHeaderKey(h)
61 }
62 return header
63 }
64
65 func (a *proxyAuth) genToken() string {
66 if a.Secret == "" {
67 return ""
68 }
69 if a.token != "" {
70 return a.token
71 }
72
73
74 h := hmac.New(sha1.New, []byte(a.Secret))
75 _, _ = h.Write([]byte(a.Username))
76 a.token = hex.EncodeToString(h.Sum(nil))
77 return a.token
78 }
79
80
81 func (a *proxyAuth) RoundTrip(req *http.Request) (*http.Response, error) {
82 if token := a.genToken(); token != "" {
83 req.Header.Set(a.header("X-Auth-CouchDB-Token"), token)
84 }
85
86 req.Header.Set(a.header("X-Auth-CouchDB-UserName"), a.Username)
87 req.Header.Set(a.header("X-Auth-CouchDB-Roles"), strings.Join(a.Roles, ","))
88
89 return a.transport.RoundTrip(req)
90 }
91
92
93 func (a *proxyAuth) Authenticate(c *Client) error {
94 a.transport = c.Transport
95 if a.transport == nil {
96 a.transport = http.DefaultTransport
97 }
98 c.Transport = a
99 return nil
100 }
101
View as plain text