/
signers.go
149 lines (131 loc) Β· 4.01 KB
/
signers.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
147
148
149
package client
import (
"fmt"
"net/http"
)
type (
// Signer is the common interface implemented by all signers.
Signer interface {
// Sign adds required headers, cookies etc.
Sign(*http.Request) error
}
// BasicSigner implements basic auth.
BasicSigner struct {
// Username is the basic auth user.
Username string
// Password is err guess what? the basic auth password.
Password string
}
// APIKeySigner implements API Key auth.
APIKeySigner struct {
// SignQuery indicates whether to set the API key in the URL query with key KeyName
// or whether to use a header with name KeyName.
SignQuery bool
// KeyName is the name of the HTTP header or query string that contains the API key.
KeyName string
// KeyValue stores the actual key.
KeyValue string
// Format is the format used to render the key, e.g. "Bearer %s"
Format string
}
// JWTSigner implements JSON Web Token auth.
JWTSigner struct {
// TokenSource is a JWT token source.
// See https://godoc.org/golang.org/x/oauth2/jwt#Config.TokenSource for an example
// of an implementation.
TokenSource TokenSource
}
// OAuth2Signer adds a authorization header to the request using the given OAuth2 token
// source to produce the header value.
OAuth2Signer struct {
// TokenSource is an OAuth2 access token source.
// See package golang/oauth2 and its subpackage for implementations of token
// sources.
TokenSource TokenSource
}
// Token is the interface to an OAuth2 token implementation.
// It can be implemented with https://godoc.org/golang.org/x/oauth2#Token.
Token interface {
// SetAuthHeader sets the Authorization header to r.
SetAuthHeader(r *http.Request)
// Valid reports whether Token can be used to properly sign requests.
Valid() bool
}
// A TokenSource is anything that can return a token.
TokenSource interface {
// Token returns a token or an error.
// Token must be safe for concurrent use by multiple goroutines.
// The returned Token must not be modified.
Token() (Token, error)
}
// StaticTokenSource implements a token source that always returns the same token.
StaticTokenSource struct {
StaticToken *StaticToken
}
// StaticToken implements a token that sets the auth header with a given static value.
StaticToken struct {
// Value used to set the auth header.
Value string
// OAuth type, defaults to "Bearer".
Type string
}
)
// Sign adds the basic auth header to the request.
func (s *BasicSigner) Sign(req *http.Request) error {
if s.Username != "" && s.Password != "" {
req.SetBasicAuth(s.Username, s.Password)
}
return nil
}
// Sign adds the API key header to the request.
func (s *APIKeySigner) Sign(req *http.Request) error {
if s.KeyName == "" {
s.KeyName = "Authorization"
}
if s.Format == "" {
s.Format = "Bearer %s"
}
name := s.KeyName
format := s.Format
val := fmt.Sprintf(format, s.KeyValue)
if s.SignQuery {
req.URL.Query().Set(name, val)
} else {
req.Header.Set(name, val)
}
return nil
}
// Sign adds the JWT auth header.
func (s *JWTSigner) Sign(req *http.Request) error {
return signFromSource(s.TokenSource, req)
}
// Sign refreshes the access token if needed and adds the OAuth header.
func (s *OAuth2Signer) Sign(req *http.Request) error {
return signFromSource(s.TokenSource, req)
}
// signFromSource generates a token using the given source and uses it to sign the request.
func signFromSource(source TokenSource, req *http.Request) error {
token, err := source.Token()
if err != nil {
return err
}
if !token.Valid() {
return fmt.Errorf("token expired or invalid")
}
token.SetAuthHeader(req)
return nil
}
// Token returns the static token.
func (s *StaticTokenSource) Token() (Token, error) {
return s.StaticToken, nil
}
// SetAuthHeader sets the Authorization header to r.
func (t *StaticToken) SetAuthHeader(r *http.Request) {
typ := t.Type
if typ == "" {
typ = "Bearer"
}
r.Header.Set("Authorization", typ+" "+t.Value)
}
// Valid reports whether Token can be used to properly sign requests.
func (t *StaticToken) Valid() bool { return true }