OLD | NEW |
1 // Copyright 2017 The LUCI Authors. All rights reserved. | 1 // Copyright 2017 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package localauth | 5 package localauth |
6 | 6 |
7 import ( | 7 import ( |
8 "crypto/subtle" | 8 "crypto/subtle" |
9 "encoding/json" | 9 "encoding/json" |
10 "fmt" | 10 "fmt" |
11 "io" | 11 "io" |
12 "mime" | 12 "mime" |
13 "net" | 13 "net" |
14 "net/http" | 14 "net/http" |
15 "regexp" | 15 "regexp" |
16 "sort" | 16 "sort" |
17 "sync" | 17 "sync" |
18 "time" | 18 "time" |
19 | 19 |
20 "golang.org/x/net/context" | 20 "golang.org/x/net/context" |
21 "golang.org/x/oauth2" | 21 "golang.org/x/oauth2" |
22 | 22 |
23 "github.com/luci/luci-go/common/auth/localauth/rpcs" | 23 "github.com/luci/luci-go/common/auth/localauth/rpcs" |
24 "github.com/luci/luci-go/common/data/rand/cryptorand" | 24 "github.com/luci/luci-go/common/data/rand/cryptorand" |
25 "github.com/luci/luci-go/common/data/stringset" | 25 "github.com/luci/luci-go/common/data/stringset" |
26 "github.com/luci/luci-go/common/errors" | |
27 "github.com/luci/luci-go/common/logging" | 26 "github.com/luci/luci-go/common/logging" |
| 27 "github.com/luci/luci-go/common/retry" |
28 "github.com/luci/luci-go/common/runtime/paniccatcher" | 28 "github.com/luci/luci-go/common/runtime/paniccatcher" |
29 "github.com/luci/luci-go/lucictx" | 29 "github.com/luci/luci-go/lucictx" |
30 ) | 30 ) |
31 | 31 |
32 // TokenGenerator produces access tokens. | 32 // TokenGenerator produces access tokens. |
33 // | 33 // |
34 // It is called to return an access token for given combination of scopes (given | 34 // It is called to return an access token for given combination of scopes (given |
35 // as a sorted list of strings without duplicates). | 35 // as a sorted list of strings without duplicates). |
36 // | 36 // |
37 // It is called for each request to the local auth server. It may be called | 37 // It is called for each request to the local auth server. It may be called |
38 // concurrently from multiple goroutines and must implement its own caching and | 38 // concurrently from multiple goroutines and must implement its own caching and |
39 // synchronization if necessary. | 39 // synchronization if necessary. |
40 // | 40 // |
41 // It is expected that the returned token lives for at least given 'lifetime' | 41 // It is expected that the returned token lives for at least given 'lifetime' |
42 // duration (which is typically on order of minutes), but it may live longer. | 42 // duration (which is typically on order of minutes), but it may live longer. |
43 // Clients may cache the returned token for the duration of its lifetime. | 43 // Clients may cache the returned token for the duration of its lifetime. |
44 // | 44 // |
45 // May return transient errors (in errors.IsTransient returning true sense). | 45 // May return transient errors (in retry.Tag.In(err) returning true |
46 // Such errors result in HTTP 500 responses. This is appropriate for non-fatal | 46 // sense). Such errors result in HTTP 500 responses. This is appropriate for |
47 // errors. Clients may immediately retry requests on such errors. | 47 // non-fatal errors. Clients may immediately retry requests on such errors. |
48 // | 48 // |
49 // Any non-transient error is considered fatal and results in an RPC-level | 49 // Any non-transient error is considered fatal and results in an RPC-level |
50 // error response ({"error": ...}). Clients must treat such responses as fatal | 50 // error response ({"error": ...}). Clients must treat such responses as fatal |
51 // and don't retry requests. | 51 // and don't retry requests. |
52 // | 52 // |
53 // If the error implements ErrorWithCode interface, the error code returned to | 53 // If the error implements ErrorWithCode interface, the error code returned to |
54 // clients will be grabbed from the error object, otherwise the error code is | 54 // clients will be grabbed from the error object, otherwise the error code is |
55 // set to -1. | 55 // set to -1. |
56 type TokenGenerator func(ctx context.Context, scopes []string, lifetime time.Dur
ation) (*oauth2.Token, error) | 56 type TokenGenerator func(ctx context.Context, scopes []string, lifetime time.Dur
ation) (*oauth2.Token, error) |
57 | 57 |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 // Route to the appropriate RPC handler. | 328 // Route to the appropriate RPC handler. |
329 response, err := h.routeToImpl(method, request) | 329 response, err := h.routeToImpl(method, request) |
330 | 330 |
331 // *protocolError are sent as HTTP errors. | 331 // *protocolError are sent as HTTP errors. |
332 if pErr, _ := err.(*protocolError); pErr != nil { | 332 if pErr, _ := err.(*protocolError); pErr != nil { |
333 http.Error(rw, pErr.Message, pErr.Status) | 333 http.Error(rw, pErr.Message, pErr.Status) |
334 return | 334 return |
335 } | 335 } |
336 | 336 |
337 // Transient errors are returned as HTTP 500 responses. | 337 // Transient errors are returned as HTTP 500 responses. |
338 » if errors.IsTransient(err) { | 338 » if retry.Tag.In(err) { |
339 http.Error(rw, fmt.Sprintf("Transient error - %s", err), http.St
atusInternalServerError) | 339 http.Error(rw, fmt.Sprintf("Transient error - %s", err), http.St
atusInternalServerError) |
340 return | 340 return |
341 } | 341 } |
342 | 342 |
343 // Fatal errors are returned as specially structured JSON responses with | 343 // Fatal errors are returned as specially structured JSON responses with |
344 // HTTP 200 code. Replace 'response' with it. | 344 // HTTP 200 code. Replace 'response' with it. |
345 if err != nil { | 345 if err != nil { |
346 fatalError := rpcs.BaseResponse{ | 346 fatalError := rpcs.BaseResponse{ |
347 ErrorCode: -1, | 347 ErrorCode: -1, |
348 ErrorMessage: err.Error(), | 348 ErrorMessage: err.Error(), |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 // Ask the token provider for the token. This may produce ErrorWithCode. | 433 // Ask the token provider for the token. This may produce ErrorWithCode. |
434 tok, err := generator(h.ctx, sortedScopes, minTokenLifetime) | 434 tok, err := generator(h.ctx, sortedScopes, minTokenLifetime) |
435 if err != nil { | 435 if err != nil { |
436 return nil, err | 436 return nil, err |
437 } | 437 } |
438 return &rpcs.GetOAuthTokenResponse{ | 438 return &rpcs.GetOAuthTokenResponse{ |
439 AccessToken: tok.AccessToken, | 439 AccessToken: tok.AccessToken, |
440 Expiry: tok.Expiry.Unix(), | 440 Expiry: tok.Expiry.Unix(), |
441 }, nil | 441 }, nil |
442 } | 442 } |
OLD | NEW |