1

BitBucket OAuth API を機能させようと、約 1 週間机に頭をぶつけてきましたが、自分の命を救うためのリクエスト トークンを 1 つも取得できません。ここで作成したコードは LinkedIn で動作しますが、BitBucket は常に HTTP ステータス コード 400 を返し、非常に詳細で役立つメッセージ「Could not verify OAuth request」が表示されます。

これは単純なコード (50 行、短くすることはできません) であり、OAuth を手動で実装する必要があるため、そのようになっています。それ以外の場合は、ここで質問したり、他の外部ライブラリを使用したりすることはありませんが、会社の要件により、そうではありませんこのプロジェクトで外部ライブラリを使用できます。何が悪いのかわかりませんが、1.0a はそれほど難しくなく、リクエスト トークンを取得するのにそれほど時間はかかりません。何が間違っている可能性がありますか?

タイムスタンプも確認しましたが、問題ありません。pool.ntp.org に対して w32tm.exe を実行すると、時刻が +30 か何かで返されます。また、UtcNow タイムスタンプに 30 分の追加と削除を試みましたが、成功しませんでしたが、時計が正しく同期されているため (現地時間と正しい GMT 値 (GMT -4:30))、まったく意味がありません。

会社のファイアウォール (Forefront) の内側にいるためでしょうか? では、LinkedIn の API 呼び出しが機能し、BitBucket が機能しないのはなぜでしょうか? また、OAuth バイブル、RFC、公式ドキュメントなどの多くのドキュメントも読みました。もちろん、質問する前に SO を広範囲に検索し、[類似の質問] パネルに表示されているすべてのリンクを確認してから、 「質問を投稿する」ボタン。

簡単なコード (C#) は次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Security.Cryptography;

namespace OAuthTest1
{
    class Program
    {
        static void Main(string[] args)
        {
            String key = "KEY";
            String secret = "SECRET";
            String requestUrl = "https://bitbucket.org/api/1.0/oauth/request_token";

            string sigBaseStringParams = "oauth_consumer_key=" + key;
            sigBaseStringParams += "&" + "oauth_nonce=" + GetNonce();
            sigBaseStringParams += "&" + "oauth_signature_method=" + "HMAC-SHA1";
            sigBaseStringParams += "&" + "oauth_timestamp=" + GetTimeStamp();
            sigBaseStringParams += "&" + "oauth_callback=http%3A%2F%2Flocal%3Fdump";
            sigBaseStringParams += "&" + "oauth_version=1.0";
            string sigBaseString = "POST&";
            sigBaseString += Uri.EscapeDataString(requestUrl) + "&" + Uri.EscapeDataString(sigBaseStringParams);

            string signature = GetSignature(sigBaseString, secret);

            Console.WriteLine(PostData(requestUrl, sigBaseStringParams + "&oauth_signature=" + Uri.EscapeDataString(signature)));
            Console.ReadKey();
        }

        public static string GetNonce()
        {
            return new Random().Next(1000000000).ToString();
        }

        public static string GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        public static String PostData(string url, string postData)
        {
            WebClient w = new WebClient();
            return w.UploadString(url, postData);
        }

        public static string GetSignature(string sigBaseString, string consumerSecretKey, string requestTokenSecretKey = null)
        {
            HMACSHA1 hmacsha1 = new HMACSHA1();
            String signingKey = string.Format("{0}&{1}", consumerSecretKey, !string.IsNullOrEmpty(requestTokenSecretKey) ? requestTokenSecretKey : "");
            hmacsha1.Key = Encoding.UTF8.GetBytes(signingKey);            
            return Convert.ToBase64String(hmacsha1.ComputeHash(Encoding.UTF8.GetBytes(sigBaseString)));
        }

    }
}

編集:リクエストによるフィドラーとブラウザのキャプチャは次のとおりです。

フィドラーとブラウザ

前もって感謝します!

編集 2: n0741337 の提案によって提供されたOAuthBase.csクラスを使用して、新しいテストを作成しましたが、そのクラスは、コールバック メソッドを要求する 1.0A 仕様に準拠していません (少なくとも Bitbucket はそれを言うのに十分親切です)。そのようなパラメーターが必要です) ので、ベース署名文字列にコールバック パラメーターが含まれるように変更する必要がありました (エンコードなしの生の形式で)。ただし、結果は同じです (いずれにせよ、秘密鍵が表示されないため、鍵を表示しても問題ないと考えました)。キャプチャは次のとおりです。

フィドラー2

そして、署名のベース文字列は次のとおりです。

GET&https%3A%2F%2Fbitbucket.org%2Fapi%2F1.0%2Foauth%2Frequest_token&oauth_callback%3Dhttp%3A%2F%2Flocalhost%3A4000%2F%26oauth_consumer_key%3Dkey%26oauth_nonce%3D8231861%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1423671576%26oauth_version%3D1.0

また、私のコードを疑問視するために、誰かがすでに Twitter に適応していることがわかったこのクラスを使用することもできます (ただし、私の職場では Twitter がブロックされているため、テストすることはできません) が、結果は同じです。

そのようなクラスを使用する、私が作成した新しいコードは次のとおりです。

using System;
using System.Net;
using System.Security.Cryptography;
using OAuth;

namespace OAuthTest1
{
    public class oauth2
    {

        public static void Run()
        {
            OAuthBase a = new OAuthBase();
            String nonce = a.GenerateNonce();
            String ts = a.GenerateTimeStamp();
            String key = "key";
            String secret = "secret";
            String requestUrl = "https://bitbucket.org/api/1.0/oauth/request_token";

            String normalizedUrl, normalizedArgs;
            String sigBase = a.GenerateSignatureBase(
                new Uri(requestUrl),
                key,
                null,
                secret,
                "http://localhost:4000/",
                "GET",
                ts,
                nonce,
                "HMAC-SHA1",
                out normalizedUrl,
                out normalizedArgs
            );
            String sig = a.GenerateSignatureUsingHash(sigBase, new HMACSHA1());

            String GETArgs = String.Empty;
            GETArgs += "oauth_consumer_key=" + key;
            GETArgs += "&oauth_nonce=" + nonce;
            GETArgs += "&oauth_signature_method=HMAC-SHA1";
            GETArgs += "&oauth_timestamp=" + ts;
            GETArgs += "&oauth_version=1.0";
            GETArgs += "&oauth_callback=" + a.UrlEncode("http://localhost:4000/");
            GETArgs += "&oauth_signature=" + sig;

            WebClient w = new WebClient();
            Console.WriteLine(w.DownloadString(requestUrl + "?" + GETArgs));

            Console.ReadKey();
        }

    }
}

編集 2 の質問:このメソッドを介して Bitbucket のサービスに接続し、Fiddler を実行して送信内容を確認できるアプリを知っている人はいますか? 出力が見られれば、少なくともフローを再現できます:/ SourceTree を試してみましたが、うまくいきません。

編集 3: AZ. の提案により、タイムスタンプ生成コードをこれで変更しましたが、とにかく動作しません:(。タイムスタンプの値は問題ないように見えますが、私のタイムスタンプとサーバーのタイムスタンプの間にはわずか 5 秒の違いしかありません:

TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
String timeStamp = Convert.ToInt64(ts.TotalSeconds).ToString();

また、署名に %20 にエンコードされているはずの「+」が含まれていることに気付きました。これは、質問を編集した後にこれに気付いたときに行ったもので、どちらも機能しません。参考までに。

Fiddler3

4

3 に答える 3

1

あなたの問題は、ローカルの開発サーバーでこれをデバッグしていて、コールバック URL として送信しているこの URL がインターネット上のクライアントには役に立たないことだと思います。

GETArgs += "&oauth_callback=" + a.UrlEncode("http://localhost:4000/");

BitBucket のドキュメントは読んでいませんが、Google OAuth の実装方法では、ハンドシェイクが機能するために、コールバック メッセージの送信先として公開されている URL が必要です。

この URL はブラウザから呼び出されるのではなく、サーバーから呼び出されるため、インターネットにアクセスできる必要があります。

于 2015-02-17T17:09:45.270 に答える