github.com/chnsz/golangsdk@v0.0.0-20240506093406-85a3fbfa605b/openstack/obs/authV4.go (about)

     1  // Copyright 2019 Huawei Technologies Co.,Ltd.
     2  // Licensed under the Apache License, Version 2.0 (the "License"); you may not use
     3  // this file except in compliance with the License.  You may obtain a copy of the
     4  // License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software distributed
     9  // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    10  // CONDITIONS OF ANY KIND, either express or implied.  See the License for the
    11  // specific language governing permissions and limitations under the License.
    12  
    13  package obs
    14  
    15  import (
    16  	"strings"
    17  	"time"
    18  )
    19  
    20  func getV4StringToSign(method, canonicalizedURL, queryURL, scope, longDate, payload string, signedHeaders []string, headers map[string][]string) string {
    21  	canonicalRequest := make([]string, 0, 10+len(signedHeaders)*4)
    22  	canonicalRequest = append(canonicalRequest, method)
    23  	canonicalRequest = append(canonicalRequest, "\n")
    24  	canonicalRequest = append(canonicalRequest, canonicalizedURL)
    25  	canonicalRequest = append(canonicalRequest, "\n")
    26  	canonicalRequest = append(canonicalRequest, queryURL)
    27  	canonicalRequest = append(canonicalRequest, "\n")
    28  
    29  	for _, signedHeader := range signedHeaders {
    30  		values, _ := headers[signedHeader]
    31  		for _, value := range values {
    32  			canonicalRequest = append(canonicalRequest, signedHeader)
    33  			canonicalRequest = append(canonicalRequest, ":")
    34  			canonicalRequest = append(canonicalRequest, value)
    35  			canonicalRequest = append(canonicalRequest, "\n")
    36  		}
    37  	}
    38  	canonicalRequest = append(canonicalRequest, "\n")
    39  	canonicalRequest = append(canonicalRequest, strings.Join(signedHeaders, ";"))
    40  	canonicalRequest = append(canonicalRequest, "\n")
    41  	canonicalRequest = append(canonicalRequest, payload)
    42  
    43  	_canonicalRequest := strings.Join(canonicalRequest, "")
    44  
    45  	var isSecurityToken bool
    46  	var securityToken []string
    47  	if securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_OBS]; !isSecurityToken {
    48  		securityToken, isSecurityToken = headers[HEADER_STS_TOKEN_AMZ]
    49  	}
    50  	var query []string
    51  	if !isSecurityToken {
    52  		query = strings.Split(queryURL, "&")
    53  		for _, value := range query {
    54  			if strings.HasPrefix(value, HEADER_STS_TOKEN_AMZ+"=") || strings.HasPrefix(value, HEADER_STS_TOKEN_OBS+"=") {
    55  				if value[len(HEADER_STS_TOKEN_AMZ)+1:] != "" {
    56  					securityToken = []string{value[len(HEADER_STS_TOKEN_AMZ)+1:]}
    57  					isSecurityToken = true
    58  				}
    59  			}
    60  		}
    61  	}
    62  	logCanonicalRequest := _canonicalRequest
    63  	if isSecurityToken && len(securityToken) > 0 {
    64  		logCanonicalRequest = strings.Replace(logCanonicalRequest, securityToken[0], "******", -1)
    65  	}
    66  	doLog(LEVEL_DEBUG, "The v4 auth canonicalRequest:\n%s", logCanonicalRequest)
    67  
    68  	stringToSign := make([]string, 0, 7)
    69  	stringToSign = append(stringToSign, V4_HASH_PREFIX)
    70  	stringToSign = append(stringToSign, "\n")
    71  	stringToSign = append(stringToSign, longDate)
    72  	stringToSign = append(stringToSign, "\n")
    73  	stringToSign = append(stringToSign, scope)
    74  	stringToSign = append(stringToSign, "\n")
    75  	stringToSign = append(stringToSign, HexSha256([]byte(_canonicalRequest)))
    76  
    77  	_stringToSign := strings.Join(stringToSign, "")
    78  
    79  	return _stringToSign
    80  }
    81  
    82  // V4Auth is a wrapper for v4Auth
    83  func V4Auth(ak, sk, region, method, canonicalizedURL, queryURL string, headers map[string][]string) map[string]string {
    84  	return v4Auth(ak, sk, region, method, canonicalizedURL, queryURL, headers)
    85  }
    86  
    87  func v4Auth(ak, sk, region, method, canonicalizedURL, queryURL string, headers map[string][]string) map[string]string {
    88  	var t time.Time
    89  	if val, ok := headers[HEADER_DATE_AMZ]; ok {
    90  		var err error
    91  		t, err = time.Parse(LONG_DATE_FORMAT, val[0])
    92  		if err != nil {
    93  			t = time.Now().UTC()
    94  		}
    95  	} else if val, ok := headers[PARAM_DATE_AMZ_CAMEL]; ok {
    96  		var err error
    97  		t, err = time.Parse(LONG_DATE_FORMAT, val[0])
    98  		if err != nil {
    99  			t = time.Now().UTC()
   100  		}
   101  	} else if val, ok := headers[HEADER_DATE_CAMEL]; ok {
   102  		var err error
   103  		t, err = time.Parse(RFC1123_FORMAT, val[0])
   104  		if err != nil {
   105  			t = time.Now().UTC()
   106  		}
   107  	} else if val, ok := headers[strings.ToLower(HEADER_DATE_CAMEL)]; ok {
   108  		var err error
   109  		t, err = time.Parse(RFC1123_FORMAT, val[0])
   110  		if err != nil {
   111  			t = time.Now().UTC()
   112  		}
   113  	} else {
   114  		t = time.Now().UTC()
   115  	}
   116  	shortDate := t.Format(SHORT_DATE_FORMAT)
   117  	longDate := t.Format(LONG_DATE_FORMAT)
   118  
   119  	signedHeaders, _headers := getSignedHeaders(headers)
   120  
   121  	credential, scope := getCredential(ak, region, shortDate)
   122  
   123  	payload := UNSIGNED_PAYLOAD
   124  	if val, ok := headers[HEADER_CONTENT_SHA256_AMZ]; ok {
   125  		payload = val[0]
   126  	}
   127  	stringToSign := getV4StringToSign(method, canonicalizedURL, queryURL, scope, longDate, payload, signedHeaders, _headers)
   128  
   129  	signature := getSignature(stringToSign, sk, region, shortDate)
   130  
   131  	ret := make(map[string]string, 3)
   132  	ret["Credential"] = credential
   133  	ret["SignedHeaders"] = strings.Join(signedHeaders, ";")
   134  	ret["Signature"] = signature
   135  	return ret
   136  }