The The request signature we calculated does not match the signature you provided error message is returned when Object Storage Service (OSS) calculates a signature from the Authorization header or a URL. This topic describes how to upload an object to OSS when you use the self-signed mode and call API operations.

Sample code

sudo python PutObject.py -h
Usage: PutObject.py [options]
Options:
  -h, --help  Display the help documentation. 
  -i AK       The AccessKey ID of the Alibaba Cloud account or RAM user. This parameter is required.
  -k SK       The AccessKey secret of the Alibaba Cloud account or the RAM user. This parameter is required.
  -e ED       The endpoint of OSS. This parameter is required.
  -b BK       The name of the OSS bucket to which you want to upload the object. This parameter is required.
  -o OBJECTS  The name of the object that you want to upload to OSS. This parameter is required.
  -f FI       The path of the local file. This parameter is required.
sudo python PutObject.py -i B0g3m**** -k lNCA4L0P**** -e oss-cn-shanghai.aliyuncs.com -b yourBucket -f localfile.txt -o aliyun.txt

Request headers

PUT /yuntest HTTP/1.1
Accept-Encoding: identity
Content-Length: 147
Connection: close
User-Agent: Python-urllib/2.7
Date: Sat, 22 Sep 2018 04:36:52 GMT
Host: yourBucket.oss-cn-shanghai.aliyuncs.com
Content-Type: application/x-www-form-urlencoded
Authorization: OSS B0g3mdt:lNCA4L0P43Ax

Response headers

HTTP/1.1 200 OK
Server: AliyunOSS
Date: Sat, 22 Sep 2018 04:36:52 GMT
Content-Length: 0
Connection: close
x-oss-request-id: 5BA5C6E4059A3C2F
ETag: "D0CAA153941AAA1CBDA38AF"
x-oss-hash-crc64ecma: 8478734191999037841
Content-MD5: 0MqhU5QbIp3Ujqqhy9o4rw==
x-oss-server-time: 15

Usage notes

  • The parameters that are used to calculate the signature are included in the Authorization header. The parameters for the header must be the same as those for signatures.
  • When you use the PUT method, you must set the Content-Type header to application/x-www-form-urlencoded to calculate signatures.
  • You cannot specify the validity period of the signature when you use the Authorization header to carry the signature information that authenticates requests. You can specify the validity period of the signature only when you use OSS SDKs or URLs.

Source code

#! /us/bin/envy python
#Author: handle
#Update: 2018-09-29
from optparse import OptionParser
import urllib, urllib2
import datetime
import base64
import hmac
import sha
import os
import sys
import time
class Main():

  # Initial input parse
  def __init__(self,options):
    self.ak = options.ak
    self.sk = options.sk
    self.ed = options.ed
    self.bk = options.bk
    self.fi = options.fi
    self.oj = options.objects
    self.left = '\033[1;31;40m'
    self.right = '\033[0m'
    self.types = "application/x-www-form-urlencoded"    
    self.url = 'http://{0}.{1}/{2}'.format(self.bk,self.ed,self.oj)
  # Check client input parse
  def CheckParse(self):
    if (self.ak and self.sk and self.ed and self.bk and self.oj and self.fi) != None:
      if str(self.ak and self.sk and self.ed and self.bk and self.oj and self.fi):
        self.PutObject()
    else:
      self.ConsoleLog("error","Input parameters cannot be empty")
  # GET local GMT time
  def GetGMT(self):

    SRM = datetime.datetime.utcnow()
    GMT = SRM.strftime('%a, %d %b %Y %H:%M:%S GMT')

    return GMT
  # GET Signature
  def GetSignature(self):
    mac = hmac.new("{0}".format(self.sk),"PUT\n\n{0}\n{1}\n/{2}/{3}".format(self.types,self.GetGMT(),self.bk,self.oj), sha)
    Signature = base64.b64encode(mac.digest())

    return Signature
  # PutObject
  def PutObject(self):

    try: 
      with open(self.fi) as fd:
        files = fd.read()
    except Exception as e:
      self.ConsoleLog("error",e)

    try:
      request = urllib2.Request(self.url, files)
      request.add_header('Host','{0}.{1}'.format(self.bk,self.ed))
      request.add_header('Date','{0}'.format(self.GetGMT()))
      request.add_header('Authorization','OSS {0}:{1}'.format(self.ak,self.GetSignature()))
      request.get_method = lambda:'PUT'
      response = urllib2.urlopen(request,timeout=10)
      fd.close()
      self.ConsoleLog(response.code,response.headers)
    except Exception,e:
      self.ConsoleLog("error",e)

  # output error log
  def ConsoleLog(self,level=None,mess=None):
    if level == "error":
      sys.exit('{0}[ERROR:]{1}{2}'.format(self.left,self.right,mess))
    else:
      sys.exit('\nHTTP/1.1 {0} OK\n{1}'.format(level,mess))

if __name__ == "__main__":
  parser = OptionParser()
  parser.add_option("-i",dest="ak",help="Must fill in AccessKey")
  parser.add_option("-k",dest="sk",help="Must fill in AccessKeySecret")
  parser.add_option("-e",dest="ed",help="Must fill in endpoint")
  parser.add_option("-b",dest="bk",help="Must fill in bucket")
  parser.add_option("-o",dest="objects",help="File name uploaded to oss")
  parser.add_option("-f",dest="fi",help="Must fill localfile path")
  (options, args) = parser.parse_args()
  handler = Main(options)
  handler.CheckParse()