1

最新の Azure SDK ストレージ エミュレーターを使用しています。ブロブへのリクエストに署名しようとしています。以下のコードを実行すると、認証エラーが発生します。

コードが Azure SDK の BLOB アクセス仕様に準拠していることを何度か確認しましたが、何が問題なのかわかりません。

コンソール出力は次のとおりです。

GET



x-ms-date:Sun, 23 Sep 2012 04:04:07 GMT
/devstoreaccount1/tweet/?comp=list
SharedKey devstoreaccount1:Hx3Pm9knGwCb4Hs9ftBX/+QlX0kCGGlUOX5g6JHZ9Kw=
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

コードは次のとおりです。

public static void signRequest(HttpURLConnection request, String account, String key) throws Exception
{
    SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
    fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
    String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";

    StringBuilder sb = new StringBuilder();
    sb.append("GET\n"); // method
    sb.append('\n'); // md5 (optional)
    sb.append('\n'); // content type
    sb.append('\n'); // legacy date
    sb.append("x-ms-date:" + date + '\n'); // headers
    sb.append(request.getURL().getPath() + "/tweet/?comp=list"); // resource TODO: "?comp=..." if present

    System.out.println(sb.toString());
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
    String authKey = new String(Base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
    String auth = "SharedKey " + account + ":" + authKey;
    request.setRequestProperty("x-ms-date", date);
    request.setRequestProperty("Authorization", auth);
    request.setRequestMethod("GET");
    System.out.println(auth);
}



public static void main(String args[]) throws Exception
{
     String account = "devstoreaccount1";
     String key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
     HttpURLConnection connection = (HttpURLConnection) (new URL("http://localhost:10000/devstoreaccount1")).openConnection();
     signRequest(connection, account, key);
     connection.connect();
     System.out.println(connection.getResponseMessage());
 }

Gaurav と Smarx からのフィードバックの後、コードは次のとおりです。それでも同じエラーが発生します。コードを見せてもらえますか?そうでないとわかりにくいです。

    public static void sign(HttpURLConnection request, String account, String key, String url) throws Exception
    {
        SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";

        StringBuilder sb = new StringBuilder();
        sb.append("GET\n"); // method
        sb.append('\n'); // md5 (optional)
        sb.append('\n'); // content type
        sb.append('\n'); // legacy date
        sb.append("x-ms-date:" + date + '\n'); // headers
        sb.append("x-ms-version:2009-09-19\n"); // headers
        sb.append("/devstoreaccount1/devstoreaccount1/\n$maxresults:1\ncomp:list\nrestype:container"); // resource TODO: "?comp=..." if present

        System.out.println(sb.toString());
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
        String authKey = new String(Base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
        String auth = "SharedKeyLite " + account + ":" + authKey;
        request.setRequestProperty("x-ms-date", date);
        request.setRequestProperty("Authorization", auth);
        request.setRequestMethod("GET");
        System.out.println(auth);
    }

    public static void main(String args[]) throws Exception
    {

        String account = "devstoreaccount1";
        String key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
        String url = "http://127.0.0.1:10000/devstoreaccount1/?restype=container&comp=list&$maxresults=1";
        HttpURLConnection connection = (HttpURLConnection) (new URL(url)).openConnection();
        sign(connection, account, key, url);
        connection.connect();
        System.out.println(connection.getResponseMessage());
    }
4

2 に答える 2

6

編集ガウラフの答えはどこに行きましたか?:-)彼はすでに回答し、あなたがShared Key Lite署名を作成しているように見えるので、認証ヘッダーで「SharedKeyLite」を使用する必要があると述べたと思います。


Gauravは彼の答えに正しいと思いますが、他に3つの問題に気づきました。

  1. を呼び出しているようですhttp://localhost/devstoreaccount1が、の署名を計算していますhttp://localhost/devstoreaccount1/tweet/?comp=list。URLが一致していることを確認してください。
  2. ストレージエミュレーターの場合、正規化されたリソースは実際にはである必要があると思います/devstoreaccount1/devstoreaccount1/tweet/?comp=list。(アカウント名の繰り返しに注意してください。)通常はである必要が/<account>/<path>あり、ストレージエミュレーターの場合、アカウント名がパスに表示されます。
  3. x-ms-versionヘッダーはどこにありますか?それが必要だと思います。

更新これは、共有キーを使用する方法と共有キーライトを使用する方法の2つの方法で機能するコードです。うまくいけば、これは物事をクリアします。ストレージエミュレータを使用するには、URLをに戻す必要があることに注意してくださいlocalhost:10000/devstoreaccount1。署名コードはエミュレーターでも機能するはずですが、私はテストしていません。Base64ライブラリはここから来ました:http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html

import java.net.*;
import java.util.*;
import java.text.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import org.apache.commons.codec.binary.Base64;

public class Test
{
    private static Base64 base64 = new Base64();

    public static void signRequestSK(HttpURLConnection request, String account, String key) throws Exception
    {
        SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";

        StringBuilder sb = new StringBuilder();
        sb.append("GET\n"); // method
        sb.append('\n'); // content encoding
        sb.append('\n'); // content language
        sb.append('\n'); // content length
        sb.append('\n'); // md5 (optional)
        sb.append('\n'); // content type
        sb.append('\n'); // legacy date
        sb.append('\n'); // if-modified-since
        sb.append('\n'); // if-match
        sb.append('\n'); // if-none-match
        sb.append('\n'); // if-unmodified-since
        sb.append('\n'); // range
        sb.append("x-ms-date:" + date + '\n'); // headers
        sb.append("x-ms-version:2009-09-19\n");
        sb.append("/" + account + request.getURL().getPath() + "\ncomp:list");

        //System.out.println(sb.toString());
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(base64.decode(key), "HmacSHA256"));
        String authKey = new String(base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
        String auth = "SharedKey " + account + ":" + authKey;
        request.setRequestProperty("x-ms-date", date);
        request.setRequestProperty("x-ms-version", "2009-09-19");
        request.setRequestProperty("Authorization", auth);
        request.setRequestMethod("GET");
        System.out.println(auth);
    }

    public static void signRequestSKL(HttpURLConnection request, String account, String key) throws Exception
    {
        SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
        fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
        String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";

        StringBuilder sb = new StringBuilder();
        sb.append("GET\n"); // method
        sb.append('\n'); // md5 (optional)
        sb.append('\n'); // content type
        sb.append('\n'); // legacy date
        sb.append("x-ms-date:" + date + '\n'); // headers
        sb.append("x-ms-version:2009-09-19\n");
        sb.append("/" + account + request.getURL().getPath() + "?comp=list");

        //System.out.println(sb.toString());
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(base64.decode(key), "HmacSHA256"));
        String authKey = new String(base64.encode(mac.doFinal(sb.toString().getBytes("UTF-8"))));
        String auth = "SharedKeyLite " + account + ":" + authKey;
        request.setRequestProperty("x-ms-date", date);
        request.setRequestProperty("x-ms-version", "2009-09-19");
        request.setRequestProperty("Authorization", auth);
        request.setRequestMethod("GET");
        System.out.println(auth);
    }



    public static void main(String args[]) throws Exception
    {
        String account = args[0];
        String key = args[1];
        HttpURLConnection connection = (HttpURLConnection) (new URL("http://" + account + ".blob.core.windows.net/?comp=list")).openConnection();
        signRequestSKL(connection, account, key);
        connection.connect();
        System.out.println(connection.getResponseMessage());

        connection = (HttpURLConnection) (new URL("http://" + account + ".blob.core.windows.net/?comp=list")).openConnection();
        signRequestSK(connection, account, key);
        connection.connect();
        System.out.println(connection.getResponseMessage());
    }
}
于 2012-09-23T04:57:19.490 に答える
0

http://msdn.microsoft.com/en-us/library/windowsazure/dd179428のドキュメントに基づいて、署名の「正規化されたリソース文字列」部分を構築する方法に問題があると思います。

私が気づいたいくつかのこと:

  • この文字列にクエリ文字列パラメーター (comp=list) を追加してはいけません。
  • 開発ストレージに対してこの文字列を作成している場合 (これを行っています)、「devstoreaccount1」が 2 回来るはずです。

たとえば、開発ストレージ アカウントで 1 つの BLOB コンテナーのみを一覧表示しようとしている場合、これは次の要求 URL に基づく正規化されたリソース文字列である必要があります - 127.0.0.1:10000/devstoreaccount1/?restype=container&comp=list&$maxresults= 1:

/devstoreaccount1/devstoreaccount1/

$maxresults:1

コンプ:リスト

restype:コンテナ

于 2012-09-23T04:47:10.117 に答える