OSDN Git Service

Create ossClient.go (#574)
[bytom/vapor.git] / vendor / github.com / aliyun / aliyun-oss-go-sdk / oss / auth.go
1 package oss
2
3 import (
4         "bytes"
5         "crypto/hmac"
6         "crypto/sha1"
7         "crypto/sha256"
8         "encoding/base64"
9         "fmt"
10         "hash"
11         "io"
12         "net/http"
13         "sort"
14         "strconv"
15         "strings"
16 )
17
18 // headerSorter defines the key-value structure for storing the sorted data in signHeader.
19 type headerSorter struct {
20         Keys []string
21         Vals []string
22 }
23
24 // getAdditionalHeaderKeys get exist key in http header
25 func (conn Conn) getAdditionalHeaderKeys(req *http.Request) ([]string, map[string]string) {
26         var keysList []string
27         keysMap := make(map[string]string)
28         srcKeys := make(map[string]string)
29
30         for k := range req.Header {
31                 srcKeys[strings.ToLower(k)] = ""
32         }
33
34         for _, v := range conn.config.AdditionalHeaders {
35                 if _, ok := srcKeys[strings.ToLower(v)]; ok {
36                         keysMap[strings.ToLower(v)] = ""
37                 }
38         }
39
40         for k := range keysMap {
41                 keysList = append(keysList, k)
42         }
43         sort.Strings(keysList)
44         return keysList, keysMap
45 }
46
47 // signHeader signs the header and sets it as the authorization header.
48 func (conn Conn) signHeader(req *http.Request, canonicalizedResource string) {
49         akIf := conn.config.GetCredentials()
50         authorizationStr := ""
51         if conn.config.AuthVersion == AuthV2 {
52                 additionalList, _ := conn.getAdditionalHeaderKeys(req)
53                 if len(additionalList) > 0 {
54                         authorizationFmt := "OSS2 AccessKeyId:%v,AdditionalHeaders:%v,Signature:%v"
55                         additionnalHeadersStr := strings.Join(additionalList, ";")
56                         authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), additionnalHeadersStr, conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()))
57                 } else {
58                         authorizationFmt := "OSS2 AccessKeyId:%v,Signature:%v"
59                         authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()))
60                 }
61         } else {
62                 // Get the final authorization string
63                 authorizationStr = "OSS " + akIf.GetAccessKeyID() + ":" + conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret())
64         }
65
66         // Give the parameter "Authorization" value
67         req.Header.Set(HTTPHeaderAuthorization, authorizationStr)
68 }
69
70 func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string, keySecret string) string {
71         // Find out the "x-oss-"'s address in header of the request
72         ossHeadersMap := make(map[string]string)
73         additionalList, additionalMap := conn.getAdditionalHeaderKeys(req)
74         for k, v := range req.Header {
75                 if strings.HasPrefix(strings.ToLower(k), "x-oss-") {
76                         ossHeadersMap[strings.ToLower(k)] = v[0]
77                 } else if conn.config.AuthVersion == AuthV2 {
78                         if _, ok := additionalMap[strings.ToLower(k)]; ok {
79                                 ossHeadersMap[strings.ToLower(k)] = v[0]
80                         }
81                 }
82         }
83         hs := newHeaderSorter(ossHeadersMap)
84
85         // Sort the ossHeadersMap by the ascending order
86         hs.Sort()
87
88         // Get the canonicalizedOSSHeaders
89         canonicalizedOSSHeaders := ""
90         for i := range hs.Keys {
91                 canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
92         }
93
94         // Give other parameters values
95         // when sign URL, date is expires
96         date := req.Header.Get(HTTPHeaderDate)
97         contentType := req.Header.Get(HTTPHeaderContentType)
98         contentMd5 := req.Header.Get(HTTPHeaderContentMD5)
99
100         // default is v1 signature
101         signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource
102         h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret))
103
104         // v2 signature
105         if conn.config.AuthVersion == AuthV2 {
106                 signStr = req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + strings.Join(additionalList, ";") + "\n" + canonicalizedResource
107                 h = hmac.New(func() hash.Hash { return sha256.New() }, []byte(keySecret))
108         }
109
110         // convert sign to log for easy to view
111         if conn.config.LogLevel >= Debug {
112                 var signBuf bytes.Buffer
113                 for i := 0; i < len(signStr); i++ {
114                         if signStr[i] != '\n' {
115                                 signBuf.WriteByte(signStr[i])
116                         } else {
117                                 signBuf.WriteString("\\n")
118                         }
119                 }
120                 conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, signBuf.String())
121         }
122
123         io.WriteString(h, signStr)
124         signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
125
126         return signedStr
127 }
128
129 func (conn Conn) getRtmpSignedStr(bucketName, channelName, playlistName string, expiration int64, keySecret string, params map[string]interface{}) string {
130         if params[HTTPParamAccessKeyID] == nil {
131                 return ""
132         }
133
134         canonResource := fmt.Sprintf("/%s/%s", bucketName, channelName)
135         canonParamsKeys := []string{}
136         for key := range params {
137                 if key != HTTPParamAccessKeyID && key != HTTPParamSignature && key != HTTPParamExpires && key != HTTPParamSecurityToken {
138                         canonParamsKeys = append(canonParamsKeys, key)
139                 }
140         }
141
142         sort.Strings(canonParamsKeys)
143         canonParamsStr := ""
144         for _, key := range canonParamsKeys {
145                 canonParamsStr = fmt.Sprintf("%s%s:%s\n", canonParamsStr, key, params[key].(string))
146         }
147
148         expireStr := strconv.FormatInt(expiration, 10)
149         signStr := expireStr + "\n" + canonParamsStr + canonResource
150
151         h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret))
152         io.WriteString(h, signStr)
153         signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
154         return signedStr
155 }
156
157 // newHeaderSorter is an additional function for function SignHeader.
158 func newHeaderSorter(m map[string]string) *headerSorter {
159         hs := &headerSorter{
160                 Keys: make([]string, 0, len(m)),
161                 Vals: make([]string, 0, len(m)),
162         }
163
164         for k, v := range m {
165                 hs.Keys = append(hs.Keys, k)
166                 hs.Vals = append(hs.Vals, v)
167         }
168         return hs
169 }
170
171 // Sort is an additional function for function SignHeader.
172 func (hs *headerSorter) Sort() {
173         sort.Sort(hs)
174 }
175
176 // Len is an additional function for function SignHeader.
177 func (hs *headerSorter) Len() int {
178         return len(hs.Vals)
179 }
180
181 // Less is an additional function for function SignHeader.
182 func (hs *headerSorter) Less(i, j int) bool {
183         return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0
184 }
185
186 // Swap is an additional function for function SignHeader.
187 func (hs *headerSorter) Swap(i, j int) {
188         hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i]
189         hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i]
190 }