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.
go-login/login/internal/oauth1/config.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
}