This repository was archived by the owner on Sep 23, 2021. It is now read-only.
forked from rpip/upvest-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauthentication.go
129 lines (110 loc) · 3.67 KB
/
authentication.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package upvest
import (
"bytes"
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"github.com/pkg/errors"
)
const (
// URLEncodeHeader is the content-type header for OuAth2
URLEncodeHeader = "application/x-www-form-urlencoded"
// clientele
oauthPath = "/clientele/oauth2/token"
grantType = "password"
scope = "read write echo transaction"
)
// Headers represent the HTTP headers sent to Upvest API
type Headers map[string]string
// AuthProvider interface for authentication mechanisms supported by Upvest API
type AuthProvider interface {
// GetHeaders returns authorization headers (or other info) to be attached to requests.
GetHeaders(method, path string, body interface{}, c *Client) (Headers, error)
}
// OAuthResponse represents succesful OAuth response
type OAuthResponse struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
RefreshToken string `json:"refresh_token"`
}
// OAuth (The OAuth2 Key Authentication) is used to authenticate requests on behalf of a user
type OAuth struct {
clientID string
clientSecret string
username string
password string
}
// KeyAuth (The API Key Authentication) is used to authenticate requests as a tenant.
type KeyAuth struct {
apiKey string
apiSecret string
apiPassphrase string
}
// GetHeaders returns authorization headers for requests as a tenant.
func (auth KeyAuth) GetHeaders(method, path string, body interface{}, c *Client) (Headers, error) {
path1, _ := joinURLs(APIVersion, path)
versionedPath := path1.String()
var headers Headers
timestamp := fmt.Sprintf("%d", makeTimestamp())
// Compose the message as a concatenation of all info we are sending along with the request
message := timestamp + method + versionedPath
if body != nil {
buf, err := jsonEncode(body)
if err != nil {
return nil, err
}
body1, _ := ioutil.ReadAll(buf)
message = message + string(body1)
}
// Generate signature, in order to prevent manipulation of payload in flight
h := hmac.New(sha512.New, []byte(auth.apiSecret))
h.Write([]byte(message))
signature := hex.EncodeToString(h.Sum(nil))
// Generate message headers
headers = Headers{
"Content-Type": "application/json",
"X-UP-API-Key": auth.apiKey,
"X-UP-API-Signature": signature,
"X-UP-API-Timestamp": timestamp,
"X-UP-API-Passphrase": auth.apiPassphrase,
"X-UP-API-Signed-Path": versionedPath,
}
return headers, nil
}
// GetHeaders returns authorization headers for requests as a clientele
func (oauth OAuth) GetHeaders(method, path string, body interface{}, c *Client) (Headers, error) {
resp, err := oauth.preFlight(c)
if err != nil {
return nil, errors.Wrap(err, "OAuth2 preflight request failed")
}
// Retrieve and return OAuth token
headers := Headers{
"Authorization": fmt.Sprintf("Bearer %s", resp.AccessToken),
"Content-Type": "application/json",
}
return headers, nil
}
func (oauth OAuth) preFlight(c *Client) (*OAuthResponse, error) {
data := url.Values{}
data.Add("grant_type", grantType)
data.Add("scope", scope)
data.Add("client_id", oauth.clientID)
data.Add("client_secret", oauth.clientSecret)
data.Add("username", oauth.username)
data.Add("password", oauth.password)
payload := bytes.NewBufferString(data.Encode())
p := &Params{}
// TODO: refactor this to pass content type to Call/CallRaw
p.AddHeader("Content-Type", URLEncodeHeader)
p.AddHeader("Cache-Control", "no-cache")
resp := &OAuthResponse{}
// err = c.CallRaw(http.MethodPost, oauthPath, buf, resp, contentType)
err := c.Call(http.MethodPost, oauthPath, payload, resp, p)
return resp, err
}