Users can add Header of Authorization in HTTP request to contain information on Signature, indicating that this message has been authorized.
Authorization ="jingdong" + " " + AccessKey + ":" + Signature; Signature =base64(HMAC-SHA1(AccessKeySecret, UTF-8-Encoding-Of( StringToSign ) ) ) StringToSign =HTTP-Verb + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedHeaders + CanonicalizedResource;
Note:
When Content-Type or Content-MD5 is absent, it shall be replaced by null character string.
You can log in to the console of JD Cloud with AccessKey and AccessKeySecret to view it in AccessKey Management. AccessKeySecret represents secret key needed for signature
HTTP-Verb represents Method requested by HTTP, mainly including PUT, GET, POST, HEAD, and DELETE.
\n represents line separator
Content-MD5 represents MD5 value of the requested content, and the message content (not including the header) is calculated for MD5 value to obtain a 128-bit number, and content-MD5 is obtained by encoding base64. The request header is available for the examination of message legality (whether a message is consistent with the sent content), such as "3fe8ebd7f5996651fa46c4aefe24b6af", and it can also be null.
Content-Type represents the class of request, such as "text/plain", and it can also be null
Date represents the time of this operation, and it must be GMT format, such as "Sun, 09 Jul 2017 06:08:40 GMT"
CanonicalizedHeaders represents the arrangement in the dictionary order of HTTP headers with prefix x-jss-.
CanonicalizedResource represents OSS resource that the user wants to access, of which Date and CanonicalizedResource canтАЩt be null; if the Date time in the request is more than 15 minutes apart from the OSS server, OSS server will deny this service, and return an HTTP 403 Error.
All HTTP Headers prefixed x-jss- are called CanonicalizedHeaders. Its building methods are as follows:
Convert all names of HTTP request headers prefixed x-jss- to lowercase.
Arrange all HTTP request headers from the last step in ascending order according to the dictionary order of the names.
Delete any space at either end of the delimiter between the request header and the content.
For example, convert x-jss-server-side-encryption: false into x-jss-server-side-encryption:false
Separate each header and content with \n delimiter and splice CanonicalizedHeaders.
If there is no HTTP request header prefixed x-jss-, CanonicalizedHeaders shall be null character string "".
Note:
CanonicalizedHeaders can be null, and itтАЩs not necessary to add the last \n.
If there is only one request header, such as x-jss-server-side-encryption:false\n, pay attention to \n at the end.
If there are more than one request headers, pay attention to "\n" at the end.
The OSS target resource to be accessed in the request sent by the user is called CanonicalizedResource. Its building methods are as follows:
Set CanonicalizedResource to a null character string "".
Put in the OSS resource to be accessed /BucketName/ObjectName(if there is no ObjectName, then CanonicalizedResource will be "/BucketName", and if there is no BucketName at the same time, it shall be "/").
Example:
Regarding API of ListParts in MultipartUpload, the CanonicalizedResource at this time: /BucketName/ObjectName?uploadId=UploadId.
Description:
Multiple query will be spliced with & and spliced after path?. For example: PUT /ObjectName?uploadId=UploadId&partNumber=PartNumber
The query signature field supported is as follows:
SUB_RESOURCESя╝Ъ"lifecycle", "location", "logging", "partNumber", "policy", "uploadId", "uploads", "versionId", "versioning", "versions", "website", "acl" RESPONSE_HEARDESя╝Ъ"contentType", "contentLanguage", "cacheControl","contentDisposition", "contentEncoding"
The signature character string must be in UTF-8 format. The signature character string containing Chinese character must be UTF-8 encoded before calculating the final signature with the AccessKeySecret.
The signature method uses HMAC-SHA1 method defined in RFC 2104, in which Key is AccessKeySecret.
Content-Type and Content-MD5 are not required in the request, but if the request requires signature verification, the null value shall be replaced by a null character string.
Signature Example
If:
AccessKey is "qbS5QXpLORrvdrmb",
AccessKeySecret is "1MYaiNh3NeN9SuxaqFjSrc7I49rWKkQCxpl9eLNZ"
Request
PUT /sign.txt HTTP/1.1 Content-Type: text/plain Content-MD5: 0c791a8c18017c7ad1675936d12bae5d x-jss-server-side-encryption: false Date: Thu, 13 Jul 2017 02:37:31 GMT Authorization: jingdong qbS5QXpLORrvdrmb: xvj2Iv7WcSwnN26XYnTq/c2YBQs= Content-Length: 20 Host: oss.cn-north-1.jcloudcs.com
Signature = base64(hmac-sha1(AccessKeySecret, HTTP-Verb + "\n" + Content-MD5 + "\n" + Content-Type + "\n" + Date + "\n" + CanonicalizedHeaders + CanonicalizedResource))
PUT\n 0c791a8c18017c7ad1675936d12bae5d\n text/plain\n Thu, 13 Jul 2017 02:37:31 GMT\n x-jss-server-side-encryption:false\n /oss-test/sign.txt
JAVA Example Code:
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; String secretKey = "1MYaiNh3NeN9SuxaqFjSrc7I49rWKkQCxpl9eLNZ"; String signString = "PUT\n0c791a8c18017c7ad1675936d12bae5d\ntext/plain\nThu, 13 Jul 2017 02:37:31 GMT\n x-jss-server-side-encryption:false\n/oss-test/sign.txt"; SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"),"HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(signingKey); byte[ ] rawHmac = mac.doFinal(signString.getBytes("UTF-8")); String signature = new String(Base64.encodeBase64(rawHmac), "UTF-8");
Authorization = "jingdong " + AccessKey + ":" + Signature, so the final Authorization is "jingdong qbS5QXpLORrvdrmb: xvj2Iv7WcSwnN26XYnTq/c2YBQs=", then plus Authorization header to compose the message to be sent finally:
PUT /sign.txt HTTP/1.1 Content-Type: text/plain Content-MD5: 0c791a8c18017c7ad1675936d12bae5d x-jss-server-side-encryption: false Date: Thu, 13 Jul 2017 02:37:31 GMT Authorization: jingdong qbS5QXpLORrvdrmb: xvj2Iv7WcSwnN26XYnTq/c2YBQs= Content-Length: 20 Host: oss.cn-north-1.jcloudcs.com
If the incoming AccessKey is absent or inactive, return 403 Forbidden. Error code: InvalidAccessKey.
The time of incoming request must be within 15 minutes after the current time of JD Cloud Object Storage Server, otherwise it will return 403 Forbidden. Error code: RequestTimeTooSkewed.
If the format of the Authorization value in the user request header is incorrect, return 400 Bad Request. Error code: InvalidToken.
All requests of JD Cloud Object Storage Service shall adopt GMT time format specified by HTTP 1.1 protocol. The date format: Wed, 22 May 2017 05:29:49 GMT
Except for using Authorization Head, the user also can add signature information in URL, then the user can forward such URL to the third party to implement authorized access.
Implementation Method:
URL Signature Example:
http://s.jcloud.com/mybucket/public/index.html?Expires=1369191796&AccessKey=9c379f079214447fad2959c4621cd6feVb797oH1&Sigature=tzEQUA%2Bj%2BUHcEp%2FBUMKeMd5bqGc%3D
The URL signature must at least include three parameters of Signature, Expires, AccessKey.
The value of the parameter Expires is a UNIX time (seconds started from UTC time 00:00 January 1, 1970), which is used to identify timeout time of such URL. The request exceeding that time will be denied. For example, the current time is 1141889060, the developer wishes to create a URL automatically invalid after 60 seconds, the Expires time can be set as 1141889120.
AccessKey, namely, is AccessKey in key.
Signature represents signature information. The algorithm for all requests supported by JD Cloud and various Header parameters making signature in URL is basically the same as the algorithm including signature in Header.
Signature=URL-Encode(Base64(HMAC-SHA1(UTF-8-Encoding-Of(SecretKey,StringToSign)))); StringToSign =HTTP-Verb + "\n" +Content-MD5 +"\n" +Content-Type +"\n" +Expires +"\n" + CanonicalizedHeaders +CanonicalizedResource;
In which, compared with the algorithm including signature in the header, the main differences are as follows:
It is required to encode the calculated signature in URL-Encode
Exchange Date in StringToSign to Expires
Simultaneous inclusion of signature in URL and Head is not supported.
Example Code:
Add JAVA example code of signature in URL:
AccessKey:9c379f079214447fad2959c4621cd6feVb797oH1
AccessKeySecret:41oUzT1opT69jpedWVg1vFTb31FvrewWSXnnZ7i1
import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; String secretKey = "41oUzT1opT69jpedWVg1vFTb31FvrewWSXnnZ7i1"; String signString = "GET\n\n\n1369191796\n/mybucket/index.html"; SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(signingKey); byte[ ] rawHmac = mac.doFinal(signString.getBytes("UTF-8")); String signature = new String(Base64.encodeBase64(rawHmac), "UTF-8");
The final URL shall be:
http://mybucket.s.jcloud.com/index.html?Expires=1369191796&AccessKey=9c379f079214447fad2959c4621cd6feVb797oH1&Signature=mBb1uuC3y2GeyeqlW5+gN/tla6s=Host: s.jcloud.com
Detail Analysis:
When using a signature method in URL, it will expose your authorized data to the Internet within the expiration time, please evaluate use risks in advance.
When adding signature in URL, the order of Signature, Expires and AccessKey can be exchanged. But if one or more of Signature and AccessKey is/are missing, return 400 error. Error code: InvalidURI.
If the current time of access is later than the Expires time set in the request, return 400 Forbidden. Error code: ExpiredToken.
When generating the signature character string, except that Date is replaced to Expires parameter, it still includes Headers such as Content-Type and Content-MD5.