github.com/aliyun/aliyun-oss-go-sdk@v3.0.2+incompatible/oss/auth.go (about) 1 package oss 2 3 import ( 4 "bytes" 5 "crypto/hmac" 6 "crypto/sha1" 7 "crypto/sha256" 8 "encoding/base64" 9 "encoding/hex" 10 "fmt" 11 "hash" 12 "io" 13 "net/http" 14 "sort" 15 "strconv" 16 "strings" 17 "time" 18 ) 19 20 // headerSorter defines the key-value structure for storing the sorted data in signHeader. 21 type headerSorter struct { 22 Keys []string 23 Vals []string 24 } 25 26 // getAdditionalHeaderKeys get exist key in http header 27 func (conn Conn) getAdditionalHeaderKeys(req *http.Request) ([]string, map[string]string) { 28 var keysList []string 29 keysMap := make(map[string]string) 30 srcKeys := make(map[string]string) 31 32 for k := range req.Header { 33 srcKeys[strings.ToLower(k)] = "" 34 } 35 36 for _, v := range conn.config.AdditionalHeaders { 37 if _, ok := srcKeys[strings.ToLower(v)]; ok { 38 keysMap[strings.ToLower(v)] = "" 39 } 40 } 41 42 for k := range keysMap { 43 keysList = append(keysList, k) 44 } 45 sort.Strings(keysList) 46 return keysList, keysMap 47 } 48 49 // getAdditionalHeaderKeysV4 get exist key in http header 50 func (conn Conn) getAdditionalHeaderKeysV4(req *http.Request) ([]string, map[string]string) { 51 var keysList []string 52 keysMap := make(map[string]string) 53 srcKeys := make(map[string]string) 54 55 for k := range req.Header { 56 srcKeys[strings.ToLower(k)] = "" 57 } 58 59 for _, v := range conn.config.AdditionalHeaders { 60 if _, ok := srcKeys[strings.ToLower(v)]; ok { 61 if !strings.EqualFold(v, HTTPHeaderContentMD5) && !strings.EqualFold(v, HTTPHeaderContentType) { 62 keysMap[strings.ToLower(v)] = "" 63 } 64 } 65 } 66 67 for k := range keysMap { 68 keysList = append(keysList, k) 69 } 70 sort.Strings(keysList) 71 return keysList, keysMap 72 } 73 74 // signHeader signs the header and sets it as the authorization header. 75 func (conn Conn) signHeader(req *http.Request, canonicalizedResource string, credentials Credentials) { 76 akIf := credentials 77 authorizationStr := "" 78 if conn.config.AuthVersion == AuthV4 { 79 strDay := "" 80 strDate := req.Header.Get(HttpHeaderOssDate) 81 if strDate == "" { 82 strDate = req.Header.Get(HTTPHeaderDate) 83 t, _ := time.Parse(http.TimeFormat, strDate) 84 strDay = t.Format("20060102") 85 } else { 86 t, _ := time.Parse(timeFormatV4, strDate) 87 strDay = t.Format("20060102") 88 } 89 signHeaderProduct := conn.config.GetSignProduct() 90 signHeaderRegion := conn.config.GetSignRegion() 91 92 additionalList, _ := conn.getAdditionalHeaderKeysV4(req) 93 if len(additionalList) > 0 { 94 authorizationFmt := "OSS4-HMAC-SHA256 Credential=%v/%v/%v/" + signHeaderProduct + "/aliyun_v4_request,AdditionalHeaders=%v,Signature=%v" 95 additionnalHeadersStr := strings.Join(additionalList, ";") 96 authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), strDay, signHeaderRegion, additionnalHeadersStr, conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), nil)) 97 } else { 98 authorizationFmt := "OSS4-HMAC-SHA256 Credential=%v/%v/%v/" + signHeaderProduct + "/aliyun_v4_request,Signature=%v" 99 authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), strDay, signHeaderRegion, conn.getSignedStrV4(req, canonicalizedResource, akIf.GetAccessKeySecret(), nil)) 100 } 101 } else if conn.config.AuthVersion == AuthV2 { 102 additionalList, _ := conn.getAdditionalHeaderKeys(req) 103 if len(additionalList) > 0 { 104 authorizationFmt := "OSS2 AccessKeyId:%v,AdditionalHeaders:%v,Signature:%v" 105 additionnalHeadersStr := strings.Join(additionalList, ";") 106 authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), additionnalHeadersStr, conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret())) 107 } else { 108 authorizationFmt := "OSS2 AccessKeyId:%v,Signature:%v" 109 authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret())) 110 } 111 } else { 112 // Get the final authorization string 113 authorizationStr = "OSS " + akIf.GetAccessKeyID() + ":" + conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()) 114 } 115 116 // Give the parameter "Authorization" value 117 req.Header.Set(HTTPHeaderAuthorization, authorizationStr) 118 } 119 120 func (conn Conn) getSignedStr(req *http.Request, canonicalizedResource string, keySecret string) string { 121 // Find out the "x-oss-"'s address in header of the request 122 ossHeadersMap := make(map[string]string) 123 additionalList, additionalMap := conn.getAdditionalHeaderKeys(req) 124 for k, v := range req.Header { 125 if strings.HasPrefix(strings.ToLower(k), "x-oss-") { 126 ossHeadersMap[strings.ToLower(k)] = v[0] 127 } else if conn.config.AuthVersion == AuthV2 { 128 if _, ok := additionalMap[strings.ToLower(k)]; ok { 129 ossHeadersMap[strings.ToLower(k)] = v[0] 130 } 131 } 132 } 133 hs := newHeaderSorter(ossHeadersMap) 134 135 // Sort the ossHeadersMap by the ascending order 136 hs.Sort() 137 138 // Get the canonicalizedOSSHeaders 139 canonicalizedOSSHeaders := "" 140 for i := range hs.Keys { 141 canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" 142 } 143 144 // Give other parameters values 145 // when sign URL, date is expires 146 date := req.Header.Get(HTTPHeaderDate) 147 contentType := req.Header.Get(HTTPHeaderContentType) 148 contentMd5 := req.Header.Get(HTTPHeaderContentMD5) 149 150 // default is v1 signature 151 signStr := req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + canonicalizedResource 152 h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret)) 153 154 // v2 signature 155 if conn.config.AuthVersion == AuthV2 { 156 signStr = req.Method + "\n" + contentMd5 + "\n" + contentType + "\n" + date + "\n" + canonicalizedOSSHeaders + strings.Join(additionalList, ";") + "\n" + canonicalizedResource 157 h = hmac.New(func() hash.Hash { return sha256.New() }, []byte(keySecret)) 158 } 159 160 if conn.config.LogLevel >= Debug { 161 conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, EscapeLFString(signStr)) 162 } 163 164 io.WriteString(h, signStr) 165 signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) 166 167 return signedStr 168 } 169 170 func (conn Conn) getSignedStrV4(req *http.Request, canonicalizedResource string, keySecret string, signingTime *time.Time) string { 171 // Find out the "x-oss-"'s address in header of the request 172 ossHeadersMap := make(map[string]string) 173 additionalList, additionalMap := conn.getAdditionalHeaderKeysV4(req) 174 for k, v := range req.Header { 175 lowKey := strings.ToLower(k) 176 if strings.EqualFold(lowKey, HTTPHeaderContentMD5) || 177 strings.EqualFold(lowKey, HTTPHeaderContentType) || 178 strings.HasPrefix(lowKey, "x-oss-") { 179 ossHeadersMap[lowKey] = strings.Trim(v[0], " ") 180 } else { 181 if _, ok := additionalMap[lowKey]; ok { 182 ossHeadersMap[lowKey] = strings.Trim(v[0], " ") 183 } 184 } 185 } 186 187 // get day,eg 20210914 188 //signingTime 189 signDate := "" 190 strDay := "" 191 if signingTime != nil { 192 signDate = signingTime.Format(timeFormatV4) 193 strDay = signingTime.Format(shortTimeFormatV4) 194 } else { 195 var t time.Time 196 // Required parameters 197 if date := req.Header.Get(HTTPHeaderDate); date != "" { 198 signDate = date 199 t, _ = time.Parse(http.TimeFormat, date) 200 } 201 202 if ossDate := req.Header.Get(HttpHeaderOssDate); ossDate != "" { 203 signDate = ossDate 204 t, _ = time.Parse(timeFormatV4, ossDate) 205 } 206 207 strDay = t.Format("20060102") 208 } 209 210 hs := newHeaderSorter(ossHeadersMap) 211 212 // Sort the ossHeadersMap by the ascending order 213 hs.Sort() 214 215 // Get the canonicalizedOSSHeaders 216 canonicalizedOSSHeaders := "" 217 for i := range hs.Keys { 218 canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n" 219 } 220 221 signStr := "" 222 223 // v4 signature 224 hashedPayload := DefaultContentSha256 225 if val := req.Header.Get(HttpHeaderOssContentSha256); val != "" { 226 hashedPayload = val 227 } 228 229 // subResource 230 resource := canonicalizedResource 231 subResource := "" 232 subPos := strings.LastIndex(canonicalizedResource, "?") 233 if subPos != -1 { 234 subResource = canonicalizedResource[subPos+1:] 235 resource = canonicalizedResource[0:subPos] 236 } 237 238 // get canonical request 239 canonicalReuqest := req.Method + "\n" + resource + "\n" + subResource + "\n" + canonicalizedOSSHeaders + "\n" + strings.Join(additionalList, ";") + "\n" + hashedPayload 240 rh := sha256.New() 241 io.WriteString(rh, canonicalReuqest) 242 hashedRequest := hex.EncodeToString(rh.Sum(nil)) 243 244 if conn.config.LogLevel >= Debug { 245 conn.config.WriteLog(Debug, "[Req:%p]CanonicalRequest:%s\n", req, EscapeLFString(canonicalReuqest)) 246 } 247 248 // Product & Region 249 signedStrV4Product := conn.config.GetSignProduct() 250 signedStrV4Region := conn.config.GetSignRegion() 251 252 signStr = "OSS4-HMAC-SHA256" + "\n" + signDate + "\n" + strDay + "/" + signedStrV4Region + "/" + signedStrV4Product + "/aliyun_v4_request" + "\n" + hashedRequest 253 if conn.config.LogLevel >= Debug { 254 conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, EscapeLFString(signStr)) 255 } 256 257 h1 := hmac.New(func() hash.Hash { return sha256.New() }, []byte("aliyun_v4"+keySecret)) 258 io.WriteString(h1, strDay) 259 h1Key := h1.Sum(nil) 260 261 h2 := hmac.New(func() hash.Hash { return sha256.New() }, h1Key) 262 io.WriteString(h2, signedStrV4Region) 263 h2Key := h2.Sum(nil) 264 265 h3 := hmac.New(func() hash.Hash { return sha256.New() }, h2Key) 266 io.WriteString(h3, signedStrV4Product) 267 h3Key := h3.Sum(nil) 268 269 h4 := hmac.New(func() hash.Hash { return sha256.New() }, h3Key) 270 io.WriteString(h4, "aliyun_v4_request") 271 h4Key := h4.Sum(nil) 272 273 h := hmac.New(func() hash.Hash { return sha256.New() }, h4Key) 274 io.WriteString(h, signStr) 275 return fmt.Sprintf("%x", h.Sum(nil)) 276 } 277 278 func (conn Conn) getRtmpSignedStr(bucketName, channelName, playlistName string, expiration int64, keySecret string, params map[string]interface{}) string { 279 if params[HTTPParamAccessKeyID] == nil { 280 return "" 281 } 282 283 canonResource := fmt.Sprintf("/%s/%s", bucketName, channelName) 284 canonParamsKeys := []string{} 285 for key := range params { 286 if key != HTTPParamAccessKeyID && key != HTTPParamSignature && key != HTTPParamExpires && key != HTTPParamSecurityToken { 287 canonParamsKeys = append(canonParamsKeys, key) 288 } 289 } 290 291 sort.Strings(canonParamsKeys) 292 canonParamsStr := "" 293 for _, key := range canonParamsKeys { 294 canonParamsStr = fmt.Sprintf("%s%s:%s\n", canonParamsStr, key, params[key].(string)) 295 } 296 297 expireStr := strconv.FormatInt(expiration, 10) 298 signStr := expireStr + "\n" + canonParamsStr + canonResource 299 300 h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(keySecret)) 301 io.WriteString(h, signStr) 302 signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil)) 303 return signedStr 304 } 305 306 // newHeaderSorter is an additional function for function SignHeader. 307 func newHeaderSorter(m map[string]string) *headerSorter { 308 hs := &headerSorter{ 309 Keys: make([]string, 0, len(m)), 310 Vals: make([]string, 0, len(m)), 311 } 312 313 for k, v := range m { 314 hs.Keys = append(hs.Keys, k) 315 hs.Vals = append(hs.Vals, v) 316 } 317 return hs 318 } 319 320 // Sort is an additional function for function SignHeader. 321 func (hs *headerSorter) Sort() { 322 sort.Sort(hs) 323 } 324 325 // Len is an additional function for function SignHeader. 326 func (hs *headerSorter) Len() int { 327 return len(hs.Vals) 328 } 329 330 // Less is an additional function for function SignHeader. 331 func (hs *headerSorter) Less(i, j int) bool { 332 return bytes.Compare([]byte(hs.Keys[i]), []byte(hs.Keys[j])) < 0 333 } 334 335 // Swap is an additional function for function SignHeader. 336 func (hs *headerSorter) Swap(i, j int) { 337 hs.Vals[i], hs.Vals[j] = hs.Vals[j], hs.Vals[i] 338 hs.Keys[i], hs.Keys[j] = hs.Keys[j], hs.Keys[i] 339 }