18 // headerSorter defines the key-value structure for storing the sorted data in signHeader.
19 type headerSorter struct {
24 // getAdditionalHeaderKeys get exist key in http header
25 func (conn Conn) getAdditionalHeaderKeys(req *http.Request) ([]string, map[string]string) {
27 keysMap := make(map[string]string)
28 srcKeys := make(map[string]string)
30 for k := range req.Header {
31 srcKeys[strings.ToLower(k)] = ""
34 for _, v := range conn.config.AdditionalHeaders {
35 if _, ok := srcKeys[strings.ToLower(v)]; ok {
36 keysMap[strings.ToLower(v)] = ""
40 for k := range keysMap {
41 keysList = append(keysList, k)
43 sort.Strings(keysList)
44 return keysList, keysMap
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()))
58 authorizationFmt := "OSS2 AccessKeyId:%v,Signature:%v"
59 authorizationStr = fmt.Sprintf(authorizationFmt, akIf.GetAccessKeyID(), conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret()))
62 // Get the final authorization string
63 authorizationStr = "OSS " + akIf.GetAccessKeyID() + ":" + conn.getSignedStr(req, canonicalizedResource, akIf.GetAccessKeySecret())
66 // Give the parameter "Authorization" value
67 req.Header.Set(HTTPHeaderAuthorization, authorizationStr)
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]
83 hs := newHeaderSorter(ossHeadersMap)
85 // Sort the ossHeadersMap by the ascending order
88 // Get the canonicalizedOSSHeaders
89 canonicalizedOSSHeaders := ""
90 for i := range hs.Keys {
91 canonicalizedOSSHeaders += hs.Keys[i] + ":" + hs.Vals[i] + "\n"
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)
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))
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))
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])
117 signBuf.WriteString("\\n")
120 conn.config.WriteLog(Debug, "[Req:%p]signStr:%s\n", req, signBuf.String())
123 io.WriteString(h, signStr)
124 signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
129 func (conn Conn) getRtmpSignedStr(bucketName, channelName, playlistName string, expiration int64, keySecret string, params map[string]interface{}) string {
130 if params[HTTPParamAccessKeyID] == nil {
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)
142 sort.Strings(canonParamsKeys)
144 for _, key := range canonParamsKeys {
145 canonParamsStr = fmt.Sprintf("%s%s:%s\n", canonParamsStr, key, params[key].(string))
148 expireStr := strconv.FormatInt(expiration, 10)
149 signStr := expireStr + "\n" + canonParamsStr + canonResource
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))
157 // newHeaderSorter is an additional function for function SignHeader.
158 func newHeaderSorter(m map[string]string) *headerSorter {
160 Keys: make([]string, 0, len(m)),
161 Vals: make([]string, 0, len(m)),
164 for k, v := range m {
165 hs.Keys = append(hs.Keys, k)
166 hs.Vals = append(hs.Vals, v)
171 // Sort is an additional function for function SignHeader.
172 func (hs *headerSorter) Sort() {
176 // Len is an additional function for function SignHeader.
177 func (hs *headerSorter) Len() int {
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
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]