Вопрос по java, request, azure, signing – Подписание запроса Java Azure

1

Я использую последний эмулятор хранилища Azure SDK. Я пытаюсь подписать запрос к моей BLOB. Когда я запускаю приведенный ниже код, я получаю ошибку аутентификации.

Я не могу понять, что не так, хотя несколько раз проверял, соответствует ли код спецификациям доступа к BLOB-объектам Azure SDK.

Вот вывод консоли:

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());
    }

Ваш Ответ

2   ответа
5

EDIT Куда делся ответ Гаурава? :-) Я полагаю, что он уже ответил и упомянул, что вы, похоже, создаете подпись Shared Key Lite и поэтому должны использовать & quot; SharedKeyLite & quot; в вашем заголовке авторизации.


Я думаю, что Гаурав прав в своем ответе, но я заметил три других вопроса:

  1. You seem to be making a call to http://localhost/devstoreaccount1, but you're computing a signature for http://localhost/devstoreaccount1/tweet/?comp=list. Make sure the URLs match up.
  2. For the storage emulator, I think your canonicalized resource should actually be /devstoreaccount1/devstoreaccount1/tweet/?comp=list. (Note the repetition of the account name.) It should generally be /<account>/<path>, and for the storage emulator, the account name shows up in the path.
  3. Where's the x-ms-version header? I believe that's required.

UPDATE Вот некоторый рабочий код с двумя методами, один из которых использует Shared Key, а другой - Shared Key Lite. Надеюсь, это прояснит ситуацию. Обратите внимание, что для использования эмулятора хранилища вы захотите переключить 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());
    }
}
@ foobarometer Не слушайте нас обоих одновременно. :-) Вы переключились на Shared Key Lite (согласно моему ответу), но используете канонизированный стиль ресурса Shared Key (согласно Gaurav). Укажите, в каком направлении вы движетесь. :-) Вы теперь использовали x-ms-версию в своей подписи, но фактически не добавили этот заголовок.
Прыгнул пистолет слишком рано :). Это не было проблемой с SharedKey / SharedKeyLite, а с тем, как строится канонизированная строка ресурсов. Обновил мой ответ.
@Steve - я сделал запрос на перечисление контейнеров BLOB-объектов (используя .Net вместо Java, но это не должно иметь никакого значения) в отношении службы BLOB-объектов хранилища для разработки, использующей SharedKey, и она работала нормально По этой причине я закончил редактировать свой ответ. Я действительно полагаю, что именно способ, которым строится канонизированная строка ресурса, вызывает проблему.
@GauravMantri Shared Key тоже подойдет, но тогда в строке-знаке отсутствует куча строк. Я пытался предложить минимальное редактирование, чтобы получить рабочую подпись.
@GauravMantri, мне больше понравился твой первый ответ. Это действительно выглядит как строка со знаком-ключом Shared Key Lite, и это нормально.
0

На основании документации здесь:http://msdn.microsoft.com/en-us/library/windowsazure/dd179428Я полагаю, что существует проблема с тем, как вы строите «Канонизированную строку ресурсов». часть вашей подписи.

Несколько вещей, которые я заметил:

  • You're appending query string parameter (comp=list) to this string which you should not.
  • If you're constructing this string against development storage (which you're doing), "devstoreaccount1" should come twice.

Например, если я пытаюсь перечислить только 1 контейнер больших двоичных объектов в моей учетной записи хранения разработки, это должна быть канонизированная строка ресурса на основе следующего URL-адреса запроса - 127.0.0.1:10000/devstoreaccount1/?restype=container&comp=list& $ maxresults = 1:

/ Devstoreaccount1 / devstoreaccount1 /

$ maxresults: 1

Комп: список

restype: контейнер

Я обновил код (выше), все та же ошибка. foobarometer

Похожие вопросы