Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 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 auth implements a wrapper around golang.org/x/oauth2. | 5 // Package auth implements a wrapper around golang.org/x/oauth2. |
| 6 // | 6 // |
| 7 // Its main improvement is the on-disk cache for OAuth tokens, which is | 7 // Its main improvement is the on-disk cache for OAuth tokens, which is |
| 8 // especially important for 3-legged interactive OAuth flows: its usage | 8 // especially important for 3-legged interactive OAuth flows: its usage |
| 9 // eliminates annoying login prompts each time a program is used (because the | 9 // eliminates annoying login prompts each time a program is used (because the |
| 10 // refresh token can now be reused). The cache also allows to reduce unnecessary | 10 // refresh token can now be reused). The cache also allows to reduce unnecessary |
| (...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 554 return nil, err | 554 return nil, err |
| 555 case useAuth: | 555 case useAuth: |
| 556 return perRPCCreds{a}, nil // token-injecting PerRPCCredentials | 556 return perRPCCreds{a}, nil // token-injecting PerRPCCredentials |
| 557 default: | 557 default: |
| 558 return perRPCCreds{}, nil // noop PerRPCCredentials | 558 return perRPCCreds{}, nil // noop PerRPCCredentials |
| 559 } | 559 } |
| 560 } | 560 } |
| 561 | 561 |
| 562 // GetAccessToken returns a valid access token with specified minimum lifetime. | 562 // GetAccessToken returns a valid access token with specified minimum lifetime. |
| 563 // | 563 // |
| 564 // | |
| 565 // Does not interact with the user. May return ErrLoginRequired. | 564 // Does not interact with the user. May return ErrLoginRequired. |
| 566 func (a *Authenticator) GetAccessToken(lifetime time.Duration) (*oauth2.Token, e rror) { | 565 func (a *Authenticator) GetAccessToken(lifetime time.Duration) (*oauth2.Token, e rror) { |
| 567 tok, err := a.currentToken() | 566 tok, err := a.currentToken() |
| 568 if err != nil { | 567 if err != nil { |
| 569 return nil, err | 568 return nil, err |
| 570 } | 569 } |
| 571 if tok == nil || internal.TokenExpiresInRnd(a.ctx, tok, lifetime) { | 570 if tok == nil || internal.TokenExpiresInRnd(a.ctx, tok, lifetime) { |
| 571 // Give 5 sec extra to make sure callers definitely receive a to ken that | |
| 572 // has at least 'lifetime' seconds of life left. Without this ma rgin, we | |
| 573 // can get into an unlucky situation where the token is valid he re, but | |
| 574 // no longer valid (has fewer than 'lifetime' life left) up the stack, due | |
| 575 // to the passage of time. | |
| 572 var err error | 576 var err error |
| 573 » » tok, err = a.refreshToken(tok, lifetime) | 577 » » tok, err = a.refreshToken(tok, lifetime+5*time.Second) |
|
iannucci
2017/06/23 00:06:18
would it make sense to tie this to the context dea
Vadim Sh.
2017/06/23 00:11:59
I don't think if will provide any value. By existi
| |
| 574 if err != nil { | 578 if err != nil { |
| 575 return nil, err | 579 return nil, err |
| 576 } | 580 } |
| 577 // Note: no randomization here. It is a sanity check that verifi es | 581 // Note: no randomization here. It is a sanity check that verifi es |
| 578 // refreshToken did its job. | 582 // refreshToken did its job. |
| 579 if internal.TokenExpiresIn(a.ctx, tok, lifetime) { | 583 if internal.TokenExpiresIn(a.ctx, tok, lifetime) { |
| 580 return nil, fmt.Errorf("auth: failed to refresh the toke n") | 584 return nil, fmt.Errorf("auth: failed to refresh the toke n") |
| 581 } | 585 } |
| 582 } | 586 } |
| 583 return tok, nil | 587 return tok, nil |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 991 }) | 995 }) |
| 992 } | 996 } |
| 993 | 997 |
| 994 //////////////////////////////////////////////////////////////////////////////// | 998 //////////////////////////////////////////////////////////////////////////////// |
| 995 // Transport implementation. | 999 // Transport implementation. |
| 996 | 1000 |
| 997 // authTokenInjector injects an authentication token into request headers. | 1001 // authTokenInjector injects an authentication token into request headers. |
| 998 // | 1002 // |
| 999 // Used as a callback for NewModifyingTransport. | 1003 // Used as a callback for NewModifyingTransport. |
| 1000 func (a *Authenticator) authTokenInjector(req *http.Request) error { | 1004 func (a *Authenticator) authTokenInjector(req *http.Request) error { |
| 1001 » // Grab a currently known token or fail if 'ensureInitialized' failed. | 1005 » switch tok, err := a.GetAccessToken(minAcceptedLifetime); { |
| 1002 » tok, err := a.currentToken() | 1006 » case err == ErrLoginRequired && a.effectiveLoginMode() == OptionalLogin: |
| 1003 » if err != nil { | 1007 » » return nil // skip auth, no need for modifications |
| 1008 » case err != nil: | |
| 1004 return err | 1009 return err |
| 1010 default: | |
| 1011 tok.SetAuthHeader(req) | |
| 1012 return nil | |
| 1005 } | 1013 } |
| 1006 | |
| 1007 // Attempt to refresh the token, if required. Revert to non-authed call if | |
| 1008 // token can't be refreshed and running in OptionalLogin mode. | |
| 1009 if tok == nil || internal.TokenExpiresInRnd(a.ctx, tok, minAcceptedLifet ime) { | |
| 1010 var err error | |
| 1011 tok, err = a.refreshToken(tok, minAcceptedLifetime) | |
| 1012 switch { | |
| 1013 case err == ErrLoginRequired && a.effectiveLoginMode() == Option alLogin: | |
| 1014 return nil // skip auth, no need for modifications | |
| 1015 case err != nil: | |
| 1016 return err | |
| 1017 // Note: no randomization here. It is a sanity check that verifi es | |
| 1018 // refreshToken did its job. | |
| 1019 case internal.TokenExpiresIn(a.ctx, tok, minAcceptedLifetime): | |
| 1020 return fmt.Errorf("auth: failed to refresh the token") | |
| 1021 } | |
| 1022 } | |
| 1023 tok.SetAuthHeader(req) | |
| 1024 return nil | |
| 1025 } | 1014 } |
| 1026 | 1015 |
| 1027 //////////////////////////////////////////////////////////////////////////////// | 1016 //////////////////////////////////////////////////////////////////////////////// |
| 1028 // tokenWithProvider implementation. | 1017 // tokenWithProvider implementation. |
| 1029 | 1018 |
| 1030 // tokenWithProvider wraps a token with provider that can update it and a cache | 1019 // tokenWithProvider wraps a token with provider that can update it and a cache |
| 1031 // that stores it. | 1020 // that stores it. |
| 1032 type tokenWithProvider struct { | 1021 type tokenWithProvider struct { |
| 1033 token *oauth2.Token // in-memory cache of the token | 1022 token *oauth2.Token // in-memory cache of the token |
| 1034 provider internal.TokenProvider // knows how to generate 'token' | 1023 provider internal.TokenProvider // knows how to generate 'token' |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1273 func makeIAMTokenProvider(ctx context.Context, opts *Options) (internal.TokenPro vider, error) { | 1262 func makeIAMTokenProvider(ctx context.Context, opts *Options) (internal.TokenPro vider, error) { |
| 1274 if opts.testingIAMTokenProvider != nil { | 1263 if opts.testingIAMTokenProvider != nil { |
| 1275 return opts.testingIAMTokenProvider, nil | 1264 return opts.testingIAMTokenProvider, nil |
| 1276 } | 1265 } |
| 1277 return internal.NewIAMTokenProvider( | 1266 return internal.NewIAMTokenProvider( |
| 1278 ctx, | 1267 ctx, |
| 1279 opts.ActAsServiceAccount, | 1268 opts.ActAsServiceAccount, |
| 1280 opts.Scopes, | 1269 opts.Scopes, |
| 1281 opts.Transport) | 1270 opts.Transport) |
| 1282 } | 1271 } |
| OLD | NEW |