github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/golang.org/x/oauth2/oauth2.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package oauth2 provides support for making 6 // OAuth2 authorized and authenticated HTTP requests. 7 // It can additionally grant authorization with Bearer JWT. 8 package oauth2 9 10 import ( 11 "bytes" 12 "errors" 13 "net/http" 14 "net/url" 15 "strings" 16 "sync" 17 18 "golang.org/x/net/context" 19 "golang.org/x/oauth2/internal" 20 ) 21 22 // NoContext is the default context you should supply if not using 23 // your own context.Context (see https://golang.org/x/net/context). 24 var NoContext = context.TODO() 25 26 // RegisterBrokenAuthHeaderProvider registers an OAuth2 server 27 // identified by the tokenURL prefix as an OAuth2 implementation 28 // which doesn't support the HTTP Basic authentication 29 // scheme to authenticate with the authorization server. 30 // Once a server is registered, credentials (client_id and client_secret) 31 // will be passed as query parameters rather than being present 32 // in the Authorization header. 33 // See https://code.google.com/p/goauth2/issues/detail?id=31 for background. 34 func RegisterBrokenAuthHeaderProvider(tokenURL string) { 35 internal.RegisterBrokenAuthHeaderProvider(tokenURL) 36 } 37 38 // Config describes a typical 3-legged OAuth2 flow, with both the 39 // client application information and the server's endpoint URLs. 40 type Config struct { 41 // ClientID is the application's ID. 42 ClientID string 43 44 // ClientSecret is the application's secret. 45 ClientSecret string 46 47 // Endpoint contains the resource server's token endpoint 48 // URLs. These are constants specific to each server and are 49 // often available via site-specific packages, such as 50 // google.Endpoint or github.Endpoint. 51 Endpoint Endpoint 52 53 // RedirectURL is the URL to redirect users going through 54 // the OAuth flow, after the resource owner's URLs. 55 RedirectURL string 56 57 // Scope specifies optional requested permissions. 58 Scopes []string 59 } 60 61 // A TokenSource is anything that can return a token. 62 type TokenSource interface { 63 // Token returns a token or an error. 64 // Token must be safe for concurrent use by multiple goroutines. 65 // The returned Token must not be modified. 66 Token() (*Token, error) 67 } 68 69 // Endpoint contains the OAuth 2.0 provider's authorization and token 70 // endpoint URLs. 71 type Endpoint struct { 72 AuthURL string 73 TokenURL string 74 } 75 76 var ( 77 // AccessTypeOnline and AccessTypeOffline are options passed 78 // to the Options.AuthCodeURL method. They modify the 79 // "access_type" field that gets sent in the URL returned by 80 // AuthCodeURL. 81 // 82 // Online is the default if neither is specified. If your 83 // application needs to refresh access tokens when the user 84 // is not present at the browser, then use offline. This will 85 // result in your application obtaining a refresh token the 86 // first time your application exchanges an authorization 87 // code for a user. 88 AccessTypeOnline AuthCodeOption = SetAuthURLParam("access_type", "online") 89 AccessTypeOffline AuthCodeOption = SetAuthURLParam("access_type", "offline") 90 91 // ApprovalForce forces the users to view the consent dialog 92 // and confirm the permissions request at the URL returned 93 // from AuthCodeURL, even if they've already done so. 94 ApprovalForce AuthCodeOption = SetAuthURLParam("approval_prompt", "force") 95 ) 96 97 // An AuthCodeOption is passed to Config.AuthCodeURL. 98 type AuthCodeOption interface { 99 setValue(url.Values) 100 } 101 102 type setParam struct{ k, v string } 103 104 func (p setParam) setValue(m url.Values) { m.Set(p.k, p.v) } 105 106 // SetAuthURLParam builds an AuthCodeOption which passes key/value parameters 107 // to a provider's authorization endpoint. 108 func SetAuthURLParam(key, value string) AuthCodeOption { 109 return setParam{key, value} 110 } 111 112 // AuthCodeURL returns a URL to OAuth 2.0 provider's consent page 113 // that asks for permissions for the required scopes explicitly. 114 // 115 // State is a token to protect the user from CSRF attacks. You must 116 // always provide a non-zero string and validate that it matches the 117 // the state query parameter on your redirect callback. 118 // See http://tools.ietf.org/html/rfc6749#section-10.12 for more info. 119 // 120 // Opts may include AccessTypeOnline or AccessTypeOffline, as well 121 // as ApprovalForce. 122 func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) string { 123 var buf bytes.Buffer 124 buf.WriteString(c.Endpoint.AuthURL) 125 v := url.Values{ 126 "response_type": {"code"}, 127 "client_id": {c.ClientID}, 128 "redirect_uri": internal.CondVal(c.RedirectURL), 129 "scope": internal.CondVal(strings.Join(c.Scopes, " ")), 130 "state": internal.CondVal(state), 131 } 132 for _, opt := range opts { 133 opt.setValue(v) 134 } 135 if strings.Contains(c.Endpoint.AuthURL, "?") { 136 buf.WriteByte('&') 137 } else { 138 buf.WriteByte('?') 139 } 140 buf.WriteString(v.Encode()) 141 return buf.String() 142 } 143 144 // PasswordCredentialsToken converts a resource owner username and password 145 // pair into a token. 146 // 147 // Per the RFC, this grant type should only be used "when there is a high 148 // degree of trust between the resource owner and the client (e.g., the client 149 // is part of the device operating system or a highly privileged application), 150 // and when other authorization grant types are not available." 151 // See https://tools.ietf.org/html/rfc6749#section-4.3 for more info. 152 // 153 // The HTTP client to use is derived from the context. 154 // If nil, http.DefaultClient is used. 155 func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error) { 156 return retrieveToken(ctx, c, url.Values{ 157 "grant_type": {"password"}, 158 "username": {username}, 159 "password": {password}, 160 "scope": internal.CondVal(strings.Join(c.Scopes, " ")), 161 }) 162 } 163 164 // Exchange converts an authorization code into a token. 165 // 166 // It is used after a resource provider redirects the user back 167 // to the Redirect URI (the URL obtained from AuthCodeURL). 168 // 169 // The HTTP client to use is derived from the context. 170 // If a client is not provided via the context, http.DefaultClient is used. 171 // 172 // The code will be in the *http.Request.FormValue("code"). Before 173 // calling Exchange, be sure to validate FormValue("state"). 174 func (c *Config) Exchange(ctx context.Context, code string) (*Token, error) { 175 return retrieveToken(ctx, c, url.Values{ 176 "grant_type": {"authorization_code"}, 177 "code": {code}, 178 "redirect_uri": internal.CondVal(c.RedirectURL), 179 "scope": internal.CondVal(strings.Join(c.Scopes, " ")), 180 }) 181 } 182 183 // Client returns an HTTP client using the provided token. 184 // The token will auto-refresh as necessary. The underlying 185 // HTTP transport will be obtained using the provided context. 186 // The returned client and its Transport should not be modified. 187 func (c *Config) Client(ctx context.Context, t *Token) *http.Client { 188 return NewClient(ctx, c.TokenSource(ctx, t)) 189 } 190 191 // TokenSource returns a TokenSource that returns t until t expires, 192 // automatically refreshing it as necessary using the provided context. 193 // 194 // Most users will use Config.Client instead. 195 func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSource { 196 tkr := &tokenRefresher{ 197 ctx: ctx, 198 conf: c, 199 } 200 if t != nil { 201 tkr.refreshToken = t.RefreshToken 202 } 203 return &reuseTokenSource{ 204 t: t, 205 new: tkr, 206 } 207 } 208 209 // tokenRefresher is a TokenSource that makes "grant_type"=="refresh_token" 210 // HTTP requests to renew a token using a RefreshToken. 211 type tokenRefresher struct { 212 ctx context.Context // used to get HTTP requests 213 conf *Config 214 refreshToken string 215 } 216 217 // WARNING: Token is not safe for concurrent access, as it 218 // updates the tokenRefresher's refreshToken field. 219 // Within this package, it is used by reuseTokenSource which 220 // synchronizes calls to this method with its own mutex. 221 func (tf *tokenRefresher) Token() (*Token, error) { 222 if tf.refreshToken == "" { 223 return nil, errors.New("oauth2: token expired and refresh token is not set") 224 } 225 226 tk, err := retrieveToken(tf.ctx, tf.conf, url.Values{ 227 "grant_type": {"refresh_token"}, 228 "refresh_token": {tf.refreshToken}, 229 }) 230 231 if err != nil { 232 return nil, err 233 } 234 if tf.refreshToken != tk.RefreshToken { 235 tf.refreshToken = tk.RefreshToken 236 } 237 return tk, err 238 } 239 240 // reuseTokenSource is a TokenSource that holds a single token in memory 241 // and validates its expiry before each call to retrieve it with 242 // Token. If it's expired, it will be auto-refreshed using the 243 // new TokenSource. 244 type reuseTokenSource struct { 245 new TokenSource // called when t is expired. 246 247 mu sync.Mutex // guards t 248 t *Token 249 } 250 251 // Token returns the current token if it's still valid, else will 252 // refresh the current token (using r.Context for HTTP client 253 // information) and return the new one. 254 func (s *reuseTokenSource) Token() (*Token, error) { 255 s.mu.Lock() 256 defer s.mu.Unlock() 257 if s.t.Valid() { 258 return s.t, nil 259 } 260 t, err := s.new.Token() 261 if err != nil { 262 return nil, err 263 } 264 s.t = t 265 return t, nil 266 } 267 268 // StaticTokenSource returns a TokenSource that always returns the same token. 269 // Because the provided token t is never refreshed, StaticTokenSource is only 270 // useful for tokens that never expire. 271 func StaticTokenSource(t *Token) TokenSource { 272 return staticTokenSource{t} 273 } 274 275 // staticTokenSource is a TokenSource that always returns the same Token. 276 type staticTokenSource struct { 277 t *Token 278 } 279 280 func (s staticTokenSource) Token() (*Token, error) { 281 return s.t, nil 282 } 283 284 // HTTPClient is the context key to use with golang.org/x/net/context's 285 // WithValue function to associate an *http.Client value with a context. 286 var HTTPClient internal.ContextKey 287 288 // NewClient creates an *http.Client from a Context and TokenSource. 289 // The returned client is not valid beyond the lifetime of the context. 290 // 291 // As a special case, if src is nil, a non-OAuth2 client is returned 292 // using the provided context. This exists to support related OAuth2 293 // packages. 294 func NewClient(ctx context.Context, src TokenSource) *http.Client { 295 if src == nil { 296 c, err := internal.ContextClient(ctx) 297 if err != nil { 298 return &http.Client{Transport: internal.ErrorTransport{err}} 299 } 300 return c 301 } 302 return &http.Client{ 303 Transport: &Transport{ 304 Base: internal.ContextTransport(ctx), 305 Source: ReuseTokenSource(nil, src), 306 }, 307 } 308 } 309 310 // ReuseTokenSource returns a TokenSource which repeatedly returns the 311 // same token as long as it's valid, starting with t. 312 // When its cached token is invalid, a new token is obtained from src. 313 // 314 // ReuseTokenSource is typically used to reuse tokens from a cache 315 // (such as a file on disk) between runs of a program, rather than 316 // obtaining new tokens unnecessarily. 317 // 318 // The initial token t may be nil, in which case the TokenSource is 319 // wrapped in a caching version if it isn't one already. This also 320 // means it's always safe to wrap ReuseTokenSource around any other 321 // TokenSource without adverse effects. 322 func ReuseTokenSource(t *Token, src TokenSource) TokenSource { 323 // Don't wrap a reuseTokenSource in itself. That would work, 324 // but cause an unnecessary number of mutex operations. 325 // Just build the equivalent one. 326 if rt, ok := src.(*reuseTokenSource); ok { 327 if t == nil { 328 // Just use it directly. 329 return rt 330 } 331 src = rt.new 332 } 333 return &reuseTokenSource{ 334 t: t, 335 new: src, 336 } 337 }