forked from Mirrors/oauth2
oauth2: fixing abstractions to be able to provide external token fetchers
This commit is contained in:
parent
c32debaa6f
commit
2af52e700e
|
@ -75,21 +75,35 @@ const (
|
||||||
uriGoogleToken = "https://accounts.google.com/o/oauth2/token"
|
uriGoogleToken = "https://accounts.google.com/o/oauth2/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ComputeEngineConfig represents a OAuth 2.0 consumer client
|
||||||
|
// running on Google Compute Engine.
|
||||||
|
type ComputeEngineConfig struct{}
|
||||||
|
|
||||||
// NewConfig creates a new OAuth2 config that uses Google
|
// NewConfig creates a new OAuth2 config that uses Google
|
||||||
// endpoints.
|
// endpoints.
|
||||||
func NewConfig(opts *oauth2.Options) (oauth2.Config, error) {
|
func NewConfig(opts *oauth2.Options) (oauth2.Config, error) {
|
||||||
return oauth2.NewConfig(opts, uriGoogleAuth, uriGoogleToken)
|
return oauth2.NewConfig(opts, uriGoogleAuth, uriGoogleToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewComputeEngineConfig creates a new config that can fetch tokens
|
|
||||||
// from Google Compute Engine instance's metaserver.
|
|
||||||
func NewComputeEngineConfig() (oauth2.Config, error) {
|
|
||||||
// Should fetch an access token from the meta server.
|
|
||||||
panic("not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServiceAccountConfig creates a new JWT config that can
|
// NewServiceAccountConfig creates a new JWT config that can
|
||||||
// fetch Bearer JWT tokens from Google endpoints.
|
// fetch Bearer JWT tokens from Google endpoints.
|
||||||
func NewServiceAccountConfig(opts *oauth2.JWTOptions) (oauth2.JWTConfig, error) {
|
func NewServiceAccountConfig(opts *oauth2.JWTOptions) (oauth2.JWTConfig, error) {
|
||||||
return oauth2.NewJWTConfig(opts, uriGoogleToken)
|
return oauth2.NewJWTConfig(opts, uriGoogleToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewComputeEngineConfig creates a new config that can fetch tokens
|
||||||
|
// from Google Compute Engine instance's metaserver.
|
||||||
|
func NewComputeEngineConfig() (*ComputeEngineConfig, error) {
|
||||||
|
// Should fetch an access token from the meta server.
|
||||||
|
return &ComputeEngineConfig{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTransport creates an authorized transport.
|
||||||
|
func (c *ComputeEngineConfig) NewTransport() (oauth2.Transport, error) {
|
||||||
|
return oauth2.NewAuthorizedTransport(c, nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FetchToken retrieves a new access token via metadata server.
|
||||||
|
func (c *ComputeEngineConfig) FetchToken(existing *oauth2.Token) (*oauth2.Token, error) {
|
||||||
|
panic("not yet implemented")
|
||||||
|
}
|
||||||
|
|
6
jwt.go
6
jwt.go
|
@ -56,18 +56,18 @@ type jwtConfig struct {
|
||||||
// NewTransport creates a transport that is authorize with the
|
// NewTransport creates a transport that is authorize with the
|
||||||
// parent JWT configuration.
|
// parent JWT configuration.
|
||||||
func (c *jwtConfig) NewTransport() (Transport, error) {
|
func (c *jwtConfig) NewTransport() (Transport, error) {
|
||||||
return &authorizedTransport{fetcher: c, token: &Token{}}, nil
|
return NewAuthorizedTransport(c, &Token{}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransportWithUser creates a transport that is authorized by
|
// NewTransportWithUser creates a transport that is authorized by
|
||||||
// the client and impersonates the specified user.
|
// the client and impersonates the specified user.
|
||||||
func (c *jwtConfig) NewTransportWithUser(user string) (Transport, error) {
|
func (c *jwtConfig) NewTransportWithUser(user string) (Transport, error) {
|
||||||
return &authorizedTransport{fetcher: c, token: &Token{Subject: user}}, nil
|
return NewAuthorizedTransport(c, &Token{Subject: user}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchToken retrieves a new access token and updates the existing token
|
// fetchToken retrieves a new access token and updates the existing token
|
||||||
// with the newly fetched credentials.
|
// with the newly fetched credentials.
|
||||||
func (c *jwtConfig) fetchToken(existing *Token) (token *Token, err error) {
|
func (c *jwtConfig) FetchToken(existing *Token) (token *Token, err error) {
|
||||||
|
|
||||||
if existing == nil {
|
if existing == nil {
|
||||||
existing = &Token{}
|
existing = &Token{}
|
||||||
|
|
26
oauth2.go
26
oauth2.go
|
@ -52,14 +52,14 @@ type tokenRespBody struct {
|
||||||
IdToken string `json:"id_token"`
|
IdToken string `json:"id_token"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// tokenFetcher refreshes or fetches a new access token from the
|
// TokenFetcher refreshes or fetches a new access token from the
|
||||||
// provider. It should return an error if it's not capable of
|
// provider. It should return an error if it's not capable of
|
||||||
// retrieving a token.
|
// retrieving a token.
|
||||||
type tokenFetcher interface {
|
type TokenFetcher interface {
|
||||||
// fetchToken retrieves a new access token for the provider.
|
// FetchToken retrieves a new access token for the provider.
|
||||||
// If the implementation doesn't know how to retrieve a new token,
|
// If the implementation doesn't know how to retrieve a new token,
|
||||||
// it returns an error.
|
// it returns an error.
|
||||||
fetchToken(existing *Token) (*Token, error)
|
FetchToken(existing *Token) (*Token, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Options represents options to provide OAuth 2.0 client credentials
|
// Options represents options to provide OAuth 2.0 client credentials
|
||||||
|
@ -120,9 +120,6 @@ type Config interface {
|
||||||
// Exchange ecxhanges the code with the provider to retrieve
|
// Exchange ecxhanges the code with the provider to retrieve
|
||||||
// a new access token.
|
// a new access token.
|
||||||
Exchange(exchangeCode string) (*Token, error)
|
Exchange(exchangeCode string) (*Token, error)
|
||||||
|
|
||||||
// TODO(jbd): Token fetcher strategy should be settable
|
|
||||||
// from external packages.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config represents an OAuth 2.0 provider and client options to
|
// Config represents an OAuth 2.0 provider and client options to
|
||||||
|
@ -136,9 +133,6 @@ type JWTConfig interface {
|
||||||
// to be authorized with OAuth 2.0 JWT Bearer flow and
|
// to be authorized with OAuth 2.0 JWT Bearer flow and
|
||||||
// impersonates the provided user.
|
// impersonates the provided user.
|
||||||
NewTransportWithUser(user string) (Transport, error)
|
NewTransportWithUser(user string) (Transport, error)
|
||||||
|
|
||||||
// TODO(jbd): Token fetcher strategy should be settable
|
|
||||||
// from external packages.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConfig creates a generic OAuth 2.0 configuration that talks
|
// NewConfig creates a generic OAuth 2.0 configuration that talks
|
||||||
|
@ -155,7 +149,7 @@ func NewConfig(opts *Options, authURL, tokenURL string) (Config, error) {
|
||||||
return conf, nil
|
return conf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// config represent the configuration of an OAuth 2.0 consumer client.
|
// config represents the configuration of an OAuth 2.0 consumer client.
|
||||||
type config struct {
|
type config struct {
|
||||||
opts *Options
|
opts *Options
|
||||||
// AuthURL is the URL the user will be directed to
|
// AuthURL is the URL the user will be directed to
|
||||||
|
@ -199,7 +193,7 @@ func (c *config) AuthCodeURL(state string) (authURL string, err error) {
|
||||||
// t.SetToken(validToken)
|
// t.SetToken(validToken)
|
||||||
//
|
//
|
||||||
func (c *config) NewTransport() (Transport, error) {
|
func (c *config) NewTransport() (Transport, error) {
|
||||||
return &authorizedTransport{fetcher: c}, nil
|
return NewAuthorizedTransport(c, nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransportWithCode exchanges the OAuth 2.0 exchange code with
|
// NewTransportWithCode exchanges the OAuth 2.0 exchange code with
|
||||||
|
@ -211,7 +205,7 @@ func (c *config) NewTransportWithCode(exchangeCode string) (Transport, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &authorizedTransport{fetcher: c, token: token}, nil
|
return NewAuthorizedTransport(c, token), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exchange exchanges the exchange code with the OAuth 2.0 provider
|
// Exchange exchanges the exchange code with the OAuth 2.0 provider
|
||||||
|
@ -230,10 +224,10 @@ func (c *config) Exchange(exchangeCode string) (*Token, error) {
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchToken retrieves a new access token and updates the existing token
|
// FetchToken retrieves a new access token and updates the existing token
|
||||||
// with the newly fetched credentials. If existing token doesn't
|
// with the newly fetched credentials. If existing token doesn't
|
||||||
// contain a refresh token, it returns an error.
|
// contain a refresh token, it returns an error.
|
||||||
func (c *config) fetchToken(existing *Token) (*Token, error) {
|
func (c *config) FetchToken(existing *Token) (*Token, error) {
|
||||||
if existing == nil || existing.RefreshToken == "" {
|
if existing == nil || existing.RefreshToken == "" {
|
||||||
return nil, errors.New("cannot fetch access token without refresh token.")
|
return nil, errors.New("cannot fetch access token without refresh token.")
|
||||||
}
|
}
|
||||||
|
@ -309,7 +303,7 @@ func (c *config) updateToken(tok *Token, v url.Values) error {
|
||||||
tok.AccessToken = resp.AccessToken
|
tok.AccessToken = resp.AccessToken
|
||||||
tok.TokenType = resp.TokenType
|
tok.TokenType = resp.TokenType
|
||||||
// Don't overwrite `RefreshToken` with an empty value
|
// Don't overwrite `RefreshToken` with an empty value
|
||||||
if resp.RefreshToken == "" {
|
if resp.RefreshToken != "" {
|
||||||
tok.RefreshToken = resp.RefreshToken
|
tok.RefreshToken = resp.RefreshToken
|
||||||
}
|
}
|
||||||
if resp.ExpiresIn == 0 {
|
if resp.ExpiresIn == 0 {
|
||||||
|
|
11
transport.go
11
transport.go
|
@ -72,13 +72,20 @@ type Transport interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type authorizedTransport struct {
|
type authorizedTransport struct {
|
||||||
fetcher tokenFetcher
|
fetcher TokenFetcher
|
||||||
token *Token
|
token *Token
|
||||||
|
|
||||||
// Mutex to protect token during auto refreshments.
|
// Mutex to protect token during auto refreshments.
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAuthorizedTransport creates a tranport that uses the provided
|
||||||
|
// token fetcher to retrieve new tokens if there is no access token
|
||||||
|
// provided or it is expired.
|
||||||
|
func NewAuthorizedTransport(fetcher TokenFetcher, token *Token) Transport {
|
||||||
|
return &authorizedTransport{fetcher: fetcher, token: token}
|
||||||
|
}
|
||||||
|
|
||||||
// RoundTrip authorizes the request with the existing token.
|
// RoundTrip authorizes the request with the existing token.
|
||||||
// If token is expired, tries to refresh/fetch a new token.
|
// If token is expired, tries to refresh/fetch a new token.
|
||||||
func (t *authorizedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
func (t *authorizedTransport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||||
|
@ -142,7 +149,7 @@ func (t *authorizedTransport) RefreshToken() error {
|
||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
|
|
||||||
token, err := t.fetcher.fetchToken(t.token)
|
token, err := t.fetcher.FetchToken(t.token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue