You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
3.8 KiB
Go
161 lines
3.8 KiB
Go
// Copyright 2017 Drone.IO Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package oauth1
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
)
|
|
|
|
// token stores the authorization credentials used to
|
|
// access protected resources.
|
|
type token struct {
|
|
Token string
|
|
TokenSecret string
|
|
}
|
|
|
|
// Config stores the application configuration.
|
|
type Config struct {
|
|
// HTTP client used to communicate with the authorization
|
|
// server. If nil, DefaultClient is used.
|
|
Client *http.Client
|
|
|
|
// A Signer signs messages to create signed OAuth1 Requests.
|
|
// If nil, the HMAC signing algorithm is used.
|
|
Signer Signer
|
|
|
|
// A value used by the Consumer to identify itself
|
|
// to the Service Provider.
|
|
ConsumerKey string
|
|
|
|
// A secret used by the Consumer to establish
|
|
// ownership of the Consumer Key.
|
|
ConsumerSecret string
|
|
|
|
// An absolute URL to which the Service Provider will redirect
|
|
// the User back when the Obtaining User Authorization step
|
|
// is completed.
|
|
//
|
|
// If the Consumer is unable to receive callbacks or a callback
|
|
// URL has been established via other means, the parameter
|
|
// value MUST be set to oob (case sensitive), to indicate
|
|
// an out-of-band configuration.
|
|
CallbackURL string
|
|
|
|
// The URL used to obtain an unauthorized
|
|
// Request Token.
|
|
RequestTokenURL string
|
|
|
|
// The URL used to obtain User authorization
|
|
// for Consumer access.
|
|
AccessTokenURL string
|
|
|
|
// The URL used to exchange the User-authorized
|
|
// Request Token for an Access Token.
|
|
AuthorizationURL string
|
|
}
|
|
|
|
// authorizeRedirect returns a client authorization
|
|
// redirect endpoint.
|
|
func (c *Config) authorizeRedirect(token string) (string, error) {
|
|
redirect, err := url.Parse(c.AuthorizationURL)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
params := make(url.Values)
|
|
params.Add("oauth_token", token)
|
|
redirect.RawQuery = params.Encode()
|
|
return redirect.String(), nil
|
|
}
|
|
|
|
// requestToken gets a request token from the server.
|
|
func (c *Config) requestToken() (*token, error) {
|
|
endpoint, err := url.Parse(c.RequestTokenURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req := &http.Request{
|
|
URL: endpoint,
|
|
Method: "POST",
|
|
ProtoMajor: 1,
|
|
ProtoMinor: 1,
|
|
Header: http.Header{},
|
|
}
|
|
err = newAuther(c).setRequestTokenAuthHeader(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res, err := c.client().Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
if res.StatusCode > 300 {
|
|
// TODO(bradrydzewski) unmarshal the oauth1 error.
|
|
return nil, errors.New("Invalid Response")
|
|
}
|
|
return parseToken(res.Body)
|
|
}
|
|
|
|
// authorizeToken returns a client authorization
|
|
// redirect endpoint.
|
|
func (c *Config) authorizeToken(token, verifier string) (*token, error) {
|
|
endpoint, err := url.Parse(c.AccessTokenURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req := &http.Request{
|
|
URL: endpoint,
|
|
Method: "POST",
|
|
ProtoMajor: 1,
|
|
ProtoMinor: 1,
|
|
Header: http.Header{},
|
|
}
|
|
err = newAuther(c).setAccessTokenAuthHeader(req, token, "", verifier)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res, err := c.client().Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer res.Body.Close()
|
|
if res.StatusCode > 300 {
|
|
x, _ := httputil.DumpResponse(res, true)
|
|
println(string(x))
|
|
// TODO(bradrydzewski) unmarshal the oauth1 error.
|
|
return nil, errors.New("Invalid Response")
|
|
}
|
|
return parseToken(res.Body)
|
|
}
|
|
|
|
func (c *Config) client() *http.Client {
|
|
client := c.Client
|
|
if client == nil {
|
|
client = http.DefaultClient
|
|
}
|
|
return client
|
|
}
|
|
|
|
func parseToken(r io.Reader) (*token, error) {
|
|
b, err := ioutil.ReadAll(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
v, err := url.ParseQuery(string(b))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &token{
|
|
Token: v.Get("oauth_token"),
|
|
TokenSecret: v.Get("oauth_token_secret"),
|
|
}, nil
|
|
}
|