2016-08-27 27 views
3

署名付きURL経由でファイルをGoogleクラウドサービスにプットできません。署名付きURLを使用するとGoogle Cloud Services putが失敗する

"SignatureDoesNotMatch ...私たちが計算したリクエストの署名が、指定した署名と一致しません.Googleの秘密鍵と署名方法を確認してください。

CURLを使用してファイルを投稿しようとすると、同じエラーが発生します。

私が使用curlコマンドは次のとおりです。私はドキュメントに基づいて、私はキーでサービスアカウントを生成しており、このキーがするために使用されるにデータをポストするつもりバケツを設定している

#!/bin/bash 
URL="https://storage.googleapis.com/..." 
echo $URL 
curl $URL -H "Content-Type: image/jpg" --upload-file b.jpg 

署名されたURLを生成します。

私は署名要求の形式は次のとおりです。

満了とバケット名を設定して計算され
PUT 

image/jpg 
1234567890 
my-bucket/b.jpg 

public String sign(PrivateKey key, String toSign) { 
    Signature signer = Signature.getInstance("SHA256withRSA"); 
    signer.initSign(key); 
    signer.update(toSign.getBytes("UTF-8")); 
    byte[] rawSignature = signer.sign(); 
    String s = new String(Base64.encodeBase64(rawSignature), "UTF-8"); 

    return s; 
} 

public String signUrl(PrivateKey key, String clientId, String method, String md5, String contentType, 
          long expiration, String gcsPath) { 

    String toSign = "${method}\n${md5}\n${contentType}\n${expiration}\n${gcsPath}"; 
    String signature = sign(key, toSign); 
    String url = java.net.URLEncoder.encode(signature); 
    return url; 
} 

public String generateSignedUrl(PrivateKey key, String clientId, String method, String md5, String contentType, 
             long expiration, String gcsPath) { 

    String canonicalizedResource = "/${gcsPath}"; 
    String signature = signUrl(key, clientId, method, md5, contentType, expiration, canonicalizedResource); 
    String finalUrl = "https://storage.googleapis.com/${gcsPath}?GoogleAccessId=${clientId}&Expires=${expiration}&Signature=${signature}" 

    finalUrl 
} 

このコードは直gsutilsのgithubのプロジェクト(https://github.com/GoogleCloudPlatform/gsutil/blob/master/gslib/tests/test_signurl.py)から持ち上げ以下通過ユニットテストを伴う:

@Test 
void thatWeCanSignAPutUrlCorrectly() { 
    String expected = """https://storage.googleapis.com/test/[email protected]&Expires=1391816302&Signature=A6QbgTA8cXZCtjy2xCr401bdi0e7zChTBQ6BX61L7AfytTGEQDMD%2BbvOQKjX7%2FsEh77cmzcSxOEKqTLUDbbkPgPqW3j8sGPSRX9VM58bgj1vt9yU8cRKoegFHXAqsATx2G5rc%2FvEliFp9UWMfVj5TaukqlBAVuzZWlyx0aQa9tCKXRtC9YcxORxG41RfiowA2kd8XBTQt4M9XTzpVyr5rVMzfr2LvtGf9UAJvlt8p6T6nThl2vy9%2FwBoPcMFaOWQcGTagwjyKWDcI1vQPIFQLGftAcv3QnGZxZTtg8pZW%2FIxRJrBhfFfcAc62hDKyaU2YssSMy%2FjUJynWx3TIiJjhg%3D%3D"""; 

    long expiration = 1391816302; 

    String signedUrl = gsUtils.generateSignedUrl(privateKey, "[email protected]","PUT", "", "", expiration, "test/test.txt") 

    assertEquals(expected, signedUrl); 
} 

Iは、署名されたURLを生成するために、次のGroovyコードを有します

あなたが提供できる洞察力が何であれありがとう、私はこの問題にしばらくおかれました。

+0

「gsutil signurl」コマンドで直接署名付きURLを生成すると、それでも失敗するのでしょうか? –

+0

こんにちは、ブランドン、あなたの助けをありがとう! gsutilsでURLを生成すると、別のエラーが発生します: '<?xml version = '1.0' encoding = 'UTF-8'?>AccessDeniedアクセスが拒否されました。

呼び出し元には、バケットmy-bucketへのstorage.objects.createアクセス権がありません。
scipio

+1

こんにちはBrandonさん、サービスアカウントをバケツの「所有者」にしてこの問題を解決しました。だから、基本的に、gsutilを使ってURLに署名し、カール経由で投稿することができます。これは素晴らしいことです!私はあなたの提案を以下にも取り組んでいます。それは少しずつです。これは最高です! – scipio

答えて

3

署名されたURLロジックをデバッグするのは難しいです。しかし、役立つ便利なトリックがあります。あなたが記述のようなエラー応答は次のようになります。

最後のビット、 <StringToSign>は、重要であること
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code> 
<Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message> 
<StringToSign>PUT 

text/jpeg 
1472720161 
/myBucket/test.txt</StringToSign></Error> 

。その中の文字列は、GCSが署名する文字列とまったく同じもので、署名する文字列です。この文字列と文字列を比較します。おそらく何らかの形で違うでしょう。

また、この署名ロジックを実装するのは難しいので、gcloud-java libraryにはsignUrl() methodがあり、ロジックを自分で実装する代わりに使用することをお勧めします。このエラーが発生する可能性があります

+0

こんにちは、ブランドン、私は問題の起源を明らかにしたことはありません。あなたが提案したAPIに切り替えました。物事はずっと良くなっているようです。ありがとうございました。 – scipio

0

一つの理由は、(前に私に起こった)あなたが署名した文字列をbase64でエンコードされた署名を生成するとき、エンコードされた署名は、不正なURL文字+/を含むことがあります。文字列の文字列をそれぞれ%2Bおよび%2Fに置き換えてください。

関連する問題