1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENSE file for details.
18
// Initialize the random generator.
20
rand.Seed(time.Now().UTC().UnixNano())
23
// Create a timestamp used in authorization header.
24
func timestamp() string {
25
return strconv.Itoa(int(time.Now().Unix()))
28
// Create a nonce used in authorization header.
30
return strconv.Itoa(rand.Intn(100000000))
33
// Contains the oauth data to perform a request.
35
ConsumerKey string `json:"consumer_key"`
36
ConsumerSecret string `json:"consumer_secret"`
37
Realm string `json:"realm"`
38
TokenKey string `json:"token_key"`
39
TokenName string `json:"token_name"`
40
TokenSecret string `json:"token_secret"`
43
type RequestParameters struct {
49
SignatureMethod SignatureMethod
52
type SignatureMethod interface {
55
ssodata *SSOData, rp *RequestParameters) (string, error)
58
type PLAINTEXT struct{}
60
// Return the name of the signature method, used to compose the
61
// Authentication Header.
62
func (PLAINTEXT) Name() string { return "PLAINTEXT" }
64
// Calculate the oaut_signature part of the Authentication Header.
65
func (PLAINTEXT) Signature(
66
ssodata *SSOData, rp *RequestParameters) (string, error) {
69
ssodata.ConsumerSecret,
70
ssodata.TokenSecret), nil
73
type HMACSHA1 struct{}
75
// Return the name of the signature method, used to compose the
76
// Authentication Header.
77
func (HMACSHA1) Name() string { return "HMAC-SHA1" }
79
// Calculate the oaut_signature part of the Authentication Header.
80
func (HMACSHA1) Signature(
81
ssodata *SSOData, rp *RequestParameters) (string, error) {
82
baseUrl, err := NormalizeURL(rp.BaseURL)
87
for k, v := range rp.Params {
90
query.Set("oauth_consumer_key", ssodata.ConsumerKey)
91
query.Set("oauth_nonce", rp.Nonce)
92
query.Set("oauth_signature_method", string(rp.SignatureMethod.Name()))
93
query.Set("oauth_timestamp", rp.Timestamp)
94
query.Set("oauth_token", ssodata.TokenKey)
95
query.Set("oauth_version", "1.0")
96
params, err := NormalizeParameters(query)
100
baseString := fmt.Sprintf("%s&%s&%s",
105
hashfun := hmac.New(sha1.New, []byte(
106
ssodata.ConsumerSecret+"&"+ssodata.TokenSecret))
107
hashfun.Write([]byte(baseString))
108
rawsignature := hashfun.Sum(nil)
109
base64signature := make(
110
[]byte, base64.StdEncoding.EncodedLen(len(rawsignature)))
111
base64.StdEncoding.Encode(base64signature, rawsignature)
112
return string(base64signature), nil
115
// Sign the provided request.
116
func (ssodata *SSOData) GetAuthorizationHeader(
117
rp *RequestParameters) (string, error) {
121
if rp.Timestamp == "" {
122
rp.Timestamp = timestamp()
124
signature, err := rp.SignatureMethod.Signature(ssodata, rp)
129
`OAuth realm="%s", `+
130
`oauth_consumer_key="%s", `+
131
`oauth_token="%s", `+
132
`oauth_signature_method="%s", `+
133
`oauth_signature="%s", `+
134
`oauth_timestamp="%s", `+
135
`oauth_nonce="%s", `+
136
`oauth_version="1.0"`,
137
url.QueryEscape(ssodata.Realm),
138
url.QueryEscape(ssodata.ConsumerKey),
139
url.QueryEscape(ssodata.TokenKey),
140
rp.SignatureMethod.Name(),
142
url.QueryEscape(rp.Timestamp),
143
url.QueryEscape(rp.Nonce))
148
// Sign the provided request.
149
func (ssodata *SSOData) SignRequest(
150
rp *RequestParameters, req *http.Request) error {
151
auth, error := ssodata.GetAuthorizationHeader(rp)
152
if req.Header == nil {
153
req.Header = make(map[string][]string)
155
req.Header.Add("Authorization", auth)