1 package autorest
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import (
18 "crypto/tls"
19 "encoding/base64"
20 "fmt"
21 "net/http"
22 "net/url"
23 "strings"
24
25 "github.com/Azure/go-autorest/autorest/adal"
26 )
27
28 const (
29 bearerChallengeHeader = "Www-Authenticate"
30 bearer = "Bearer"
31 tenantID = "tenantID"
32 apiKeyAuthorizerHeader = "Ocp-Apim-Subscription-Key"
33 bingAPISdkHeader = "X-BingApis-SDK-Client"
34 golangBingAPISdkHeaderValue = "Go-SDK"
35 authorization = "Authorization"
36 basic = "Basic"
37 )
38
39
40
41
42 type Authorizer interface {
43 WithAuthorization() PrepareDecorator
44 }
45
46
47 type NullAuthorizer struct{}
48
49
50 func (na NullAuthorizer) WithAuthorization() PrepareDecorator {
51 return WithNothing()
52 }
53
54
55 type APIKeyAuthorizer struct {
56 headers map[string]interface{}
57 queryParameters map[string]interface{}
58 }
59
60
61 func NewAPIKeyAuthorizerWithHeaders(headers map[string]interface{}) *APIKeyAuthorizer {
62 return NewAPIKeyAuthorizer(headers, nil)
63 }
64
65
66 func NewAPIKeyAuthorizerWithQueryParameters(queryParameters map[string]interface{}) *APIKeyAuthorizer {
67 return NewAPIKeyAuthorizer(nil, queryParameters)
68 }
69
70
71 func NewAPIKeyAuthorizer(headers map[string]interface{}, queryParameters map[string]interface{}) *APIKeyAuthorizer {
72 return &APIKeyAuthorizer{headers: headers, queryParameters: queryParameters}
73 }
74
75
76 func (aka *APIKeyAuthorizer) WithAuthorization() PrepareDecorator {
77 return func(p Preparer) Preparer {
78 return DecoratePreparer(p, WithHeaders(aka.headers), WithQueryParameters(aka.queryParameters))
79 }
80 }
81
82
83 type CognitiveServicesAuthorizer struct {
84 subscriptionKey string
85 }
86
87
88 func NewCognitiveServicesAuthorizer(subscriptionKey string) *CognitiveServicesAuthorizer {
89 return &CognitiveServicesAuthorizer{subscriptionKey: subscriptionKey}
90 }
91
92
93 func (csa *CognitiveServicesAuthorizer) WithAuthorization() PrepareDecorator {
94 headers := make(map[string]interface{})
95 headers[apiKeyAuthorizerHeader] = csa.subscriptionKey
96 headers[bingAPISdkHeader] = golangBingAPISdkHeaderValue
97
98 return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
99 }
100
101
102 type BearerAuthorizer struct {
103 tokenProvider adal.OAuthTokenProvider
104 }
105
106
107 func NewBearerAuthorizer(tp adal.OAuthTokenProvider) *BearerAuthorizer {
108 return &BearerAuthorizer{tokenProvider: tp}
109 }
110
111
112
113
114
115 func (ba *BearerAuthorizer) WithAuthorization() PrepareDecorator {
116 return func(p Preparer) Preparer {
117 return PreparerFunc(func(r *http.Request) (*http.Request, error) {
118 r, err := p.Prepare(r)
119 if err == nil {
120
121 if refresher, ok := ba.tokenProvider.(adal.RefresherWithContext); ok {
122 err = refresher.EnsureFreshWithContext(r.Context())
123 } else if refresher, ok := ba.tokenProvider.(adal.Refresher); ok {
124 err = refresher.EnsureFresh()
125 }
126 if err != nil {
127 var resp *http.Response
128 if tokError, ok := err.(adal.TokenRefreshError); ok {
129 resp = tokError.Response()
130 }
131 return r, NewErrorWithError(err, "azure.BearerAuthorizer", "WithAuthorization", resp,
132 "Failed to refresh the Token for request to %s", r.URL)
133 }
134 return Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", ba.tokenProvider.OAuthToken())))
135 }
136 return r, err
137 })
138 }
139 }
140
141
142 func (ba *BearerAuthorizer) TokenProvider() adal.OAuthTokenProvider {
143 return ba.tokenProvider
144 }
145
146
147 type BearerAuthorizerCallbackFunc func(tenantID, resource string) (*BearerAuthorizer, error)
148
149
150 type BearerAuthorizerCallback struct {
151 sender Sender
152 callback BearerAuthorizerCallbackFunc
153 }
154
155
156
157 func NewBearerAuthorizerCallback(s Sender, callback BearerAuthorizerCallbackFunc) *BearerAuthorizerCallback {
158 if s == nil {
159 s = sender(tls.RenegotiateNever)
160 }
161 return &BearerAuthorizerCallback{sender: s, callback: callback}
162 }
163
164
165
166
167
168 func (bacb *BearerAuthorizerCallback) WithAuthorization() PrepareDecorator {
169 return func(p Preparer) Preparer {
170 return PreparerFunc(func(r *http.Request) (*http.Request, error) {
171 r, err := p.Prepare(r)
172 if err == nil {
173
174
175 rCopy := *r
176 removeRequestBody(&rCopy)
177
178 resp, err := bacb.sender.Do(&rCopy)
179 if err != nil {
180 return r, err
181 }
182 DrainResponseBody(resp)
183 if resp.StatusCode == 401 && hasBearerChallenge(resp.Header) {
184 bc, err := newBearerChallenge(resp.Header)
185 if err != nil {
186 return r, err
187 }
188 if bacb.callback != nil {
189 ba, err := bacb.callback(bc.values[tenantID], bc.values["resource"])
190 if err != nil {
191 return r, err
192 }
193 return Prepare(r, ba.WithAuthorization())
194 }
195 }
196 }
197 return r, err
198 })
199 }
200 }
201
202
203 func hasBearerChallenge(header http.Header) bool {
204 authHeader := header.Get(bearerChallengeHeader)
205 if len(authHeader) == 0 || strings.Index(authHeader, bearer) < 0 {
206 return false
207 }
208 return true
209 }
210
211 type bearerChallenge struct {
212 values map[string]string
213 }
214
215 func newBearerChallenge(header http.Header) (bc bearerChallenge, err error) {
216 challenge := strings.TrimSpace(header.Get(bearerChallengeHeader))
217 trimmedChallenge := challenge[len(bearer)+1:]
218
219
220 pairs := strings.Split(trimmedChallenge, ",")
221 if len(pairs) < 1 {
222 err = fmt.Errorf("challenge '%s' contains no pairs", challenge)
223 return bc, err
224 }
225
226 bc.values = make(map[string]string)
227 for i := range pairs {
228 trimmedPair := strings.TrimSpace(pairs[i])
229 pair := strings.Split(trimmedPair, "=")
230 if len(pair) == 2 {
231
232 key := strings.Trim(pair[0], "\"")
233 value := strings.Trim(pair[1], "\"")
234
235 switch key {
236 case "authorization", "authorization_uri":
237
238 asURL, err := url.Parse(value)
239 if err != nil {
240 return bc, err
241 }
242 bc.values[tenantID] = asURL.Path[1:]
243 default:
244 bc.values[key] = value
245 }
246 }
247 }
248
249 return bc, err
250 }
251
252
253 type EventGridKeyAuthorizer struct {
254 topicKey string
255 }
256
257
258
259 func NewEventGridKeyAuthorizer(topicKey string) EventGridKeyAuthorizer {
260 return EventGridKeyAuthorizer{topicKey: topicKey}
261 }
262
263
264 func (egta EventGridKeyAuthorizer) WithAuthorization() PrepareDecorator {
265 headers := map[string]interface{}{
266 "aeg-sas-key": egta.topicKey,
267 }
268 return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
269 }
270
271
272
273 type BasicAuthorizer struct {
274 userName string
275 password string
276 }
277
278
279 func NewBasicAuthorizer(userName, password string) *BasicAuthorizer {
280 return &BasicAuthorizer{
281 userName: userName,
282 password: password,
283 }
284 }
285
286
287
288 func (ba *BasicAuthorizer) WithAuthorization() PrepareDecorator {
289 headers := make(map[string]interface{})
290 headers[authorization] = basic + " " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", ba.userName, ba.password)))
291
292 return NewAPIKeyAuthorizerWithHeaders(headers).WithAuthorization()
293 }
294
295
296 type MultiTenantServicePrincipalTokenAuthorizer interface {
297 WithAuthorization() PrepareDecorator
298 }
299
300
301 func NewMultiTenantServicePrincipalTokenAuthorizer(tp adal.MultitenantOAuthTokenProvider) MultiTenantServicePrincipalTokenAuthorizer {
302 return NewMultiTenantBearerAuthorizer(tp)
303 }
304
305
306 type MultiTenantBearerAuthorizer struct {
307 tp adal.MultitenantOAuthTokenProvider
308 }
309
310
311 func NewMultiTenantBearerAuthorizer(tp adal.MultitenantOAuthTokenProvider) *MultiTenantBearerAuthorizer {
312 return &MultiTenantBearerAuthorizer{tp: tp}
313 }
314
315
316
317
318
319 func (mt *MultiTenantBearerAuthorizer) WithAuthorization() PrepareDecorator {
320 return func(p Preparer) Preparer {
321 return PreparerFunc(func(r *http.Request) (*http.Request, error) {
322 r, err := p.Prepare(r)
323 if err != nil {
324 return r, err
325 }
326 if refresher, ok := mt.tp.(adal.RefresherWithContext); ok {
327 err = refresher.EnsureFreshWithContext(r.Context())
328 if err != nil {
329 var resp *http.Response
330 if tokError, ok := err.(adal.TokenRefreshError); ok {
331 resp = tokError.Response()
332 }
333 return r, NewErrorWithError(err, "azure.multiTenantSPTAuthorizer", "WithAuthorization", resp,
334 "Failed to refresh one or more Tokens for request to %s", r.URL)
335 }
336 }
337 r, err = Prepare(r, WithHeader(headerAuthorization, fmt.Sprintf("Bearer %s", mt.tp.PrimaryOAuthToken())))
338 if err != nil {
339 return r, err
340 }
341 auxTokens := mt.tp.AuxiliaryOAuthTokens()
342 for i := range auxTokens {
343 auxTokens[i] = fmt.Sprintf("Bearer %s", auxTokens[i])
344 }
345 return Prepare(r, WithHeader(headerAuxAuthorization, strings.Join(auxTokens, ", ")))
346 })
347 }
348 }
349
350
351 func (mt *MultiTenantBearerAuthorizer) TokenProvider() adal.MultitenantOAuthTokenProvider {
352 return mt.tp
353 }
354
View as plain text