Ceph RGW服務 使用s3 java sdk 分片文件上傳API 報‘SignatureDoesNotMatch’ 異常的定位及規避方案

 importjava.io.File;
 
import  com.amazonaws.AmazonClientException;
 
 
import  com.amazonaws.auth.profile.ProfileCredentialsProvider;
 
 
import  com.amazonaws.services.s3.transfer.TransferManager;
 
 
import  com.amazonaws.services.s3.transfer.Upload;
 
 
 
 
 
public  class  UploadObjectMultipartUploadUsingHighLevelAPI {
 
 
 
     public  static  void  main(String[] args)  throws  Exception {
 
 
         String existingBucketName =  "*** Provide existing bucket name ***" ;
 
 
         String keyName            =  "*** Provide object key ***" ;
 
 
         String filePath           =  "*** Path to and name of the file to upload ***"
 
 
         
 
 
         TransferManager tm =  new  TransferManager( new  ProfileCredentialsProvider());       
 
 
         System.out.println( "Hello" );
 
 
         // TransferManager processes all transfers asynchronously,
 
 
         // so this call will return immediately.
 
 
         Upload upload = tm.upload(
 
 
                 existingBucketName, keyName,  new  File(filePath));
 
 
         System.out.println( "Hello2" );
 
 
 
 
 
         try  {
 
 
             // Or you can block and wait for the upload to finish
 
 
             upload.waitForCompletion();
 
 
             System.out.println( "Upload complete." );
 
 
         catch  (AmazonClientException amazonClientException) {
 
 
             System.out.println( "Unable to upload file, upload was aborted." );
 
 
             amazonClientException.printStackTrace();
 
 
         }
 
 
     }
 
 
}
 

問題描述:使用s3 java sdk 的如上代碼分片文件上傳,報‘SignatureDoesNotMatch’ 異常以下html

Unable to abort multipart upload, you may need to manually remove uploaded parts: null (Service: Amazon S3; Status Code: 403; Error Code: SignatureDoesNotMatch; Request ID: tx000000000000000003ddf-005853b76e-1a56f9b-default)
com.amazonaws.services.s3.model.AmazonS3Exception: null (Service: Amazon S3; Status Code: 403; Error Code: SignatureDoesNotMatch; Request ID: tx000000000000000003ddf-005853b76e-1a56f9b-default), S3 Extended Request ID: 1a56f9b-default-defaultjava

 

 

 

定位過程:git

下載s3 java sdk 源碼,並配置好 log4j, 打印aws debug日誌; github

# For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml!
# For all other servers: Comment out the Log4J listener in web.xml to activate Log4J.
#log4j.rootLogger=INFO, stdout, logfile
log4j.rootLogger=INFO,stdout,logfile
log4j.logger.com.amazonaws = DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n

RGW配置文件/etc/ceph/ceph.conf 中的日誌級別調整爲20,重啓RGW進程web

debug rgw = 20apache

 

執行分片上傳代碼,分別截獲客戶端和服務端的請求日誌。 以下2個圖片能夠發現uploadId客戶端和服務端不一致,致使服務端進行簽名校驗失敗。app

 

 

 

  

那麼問題來了,究竟是RGW服務端,仍是java s3 sdk實現有bug呢? 經過查看java 代碼和aws文檔描述,我認爲是RGW簽名實現存在bug。 RGW 應該在async

獲取從客戶端url中的參數中值(已經被URLEncode)後,先decode,再根據aws文檔描述的步驟進行encode(~特殊字符不encode),獲得符合規則的參數字符串。 ide

.\src\rgw\rgw_rest_s3.ccthis

 

http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

 

 

規避方案:

 

由於修改RGW的代碼週期比較長,暫時先修改好修改的java代碼,編譯一個新的jar包。 以下是修改方法,不按照aws的規則來,對參數值只執行URLencode。

提交了一個bugfix到rgw git庫, https://github.com/ceph/ceph/pull/12647/commits

 

 https://github.com/BodihTao/aws-sdk-java/blob/master/aws-java-sdk-core/src/main/java/com/amazonaws/auth/AbstractAWSSigner.java

 

爲了方便你們,我上傳修改後編譯好的class文件(java 1.8版本),把這2個文件用winrar 放到aws-java-sdk-1.11.69.jar包中com/amazonaws/auth目錄下 替換原來文件便可獲得新的jar包。

https://github.com/BodihTao/aws-sdk-java/raw/master/aws-java-sdk/AbstractAWSSigner%241.class

https://github.com/BodihTao/aws-sdk-java/raw/master/aws-java-sdk/AbstractAWSSigner.class

 

java 1.7版本的sdk包:

http://s3.yyclouds.com/public/aws-java-sdk-1.11.69rgw.jar

相關文章
相關標籤/搜索