为什么BitBucket OAuth request_token API总是返回400“无法验证OAuth请求”?

暗黑的家伙

为了使BitBucket OAuth API正常工作,我一直在桌子上敲打头整整一周,甚至无法获得一个请求令牌来挽救自己的生命。我在此处创建的代码可用于LinkedIn,但BitBucket始终返回HTTP状态代码400,其中包含一条非常冗长且有用的消息:“无法验证OAuth请求”。

这是一个简单的代码(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

Also, to put my code in doubt, one can also use this class I found which someone already adapted for Twitter (though Twitter is blocked in my workplace so I can't test against it), but the results are the same.

Here's the new code I made which uses such classes:

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

    }
}

Question for Edit 2: Does anyone know of an app which connects to Bitbucket's service through this method so I can run Fiddler and see what it is sending? If I could see some output I could at least replicate the flow :/ I've tried against SourceTree but it doesn't work very well.

Edit 3: By AZ.'s suggestion I changed the timestamp generation code with this, but it doesn't work anyways :(. Timestamp values look okay though, there's only a slight difference of 5 seconds between my timestamp and the server's:

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

Also, I notice the signature contains a "+" which should've been encoded to %20, which I did when I noticed this after editing the question and it doesn't work either, just FYI.

提琴手3

Erik van Zijst

There are 2 things wrong with your program:

  • You're not sending the Content-Type: application/x-www-form-urlencoded header, which makes the POST body unintelligible (it's generally recommended to use the Authorization request header).
  • 您没有正确创建签名基本字符串。签名基本字符串是OAuth 1.0中最精致的部分,因为客户端和服务器都必须独立产生完全相同的字节序列。使用时,oauth_callback您会弄错参数的顺序(http://oauth.net/core/1.0/#anchor14

这是使程序正常运行的补丁:

--- Program.cs  2015-02-23 23:13:03.000000000 -0800
+++ Program3.cs 2015-02-23 23:20:37.000000000 -0800
@@ -15,11 +15,12 @@
             String secret = "SECRET";
             String requestUrl = "https://bitbucket.org/api/1.0/oauth/request_token";

-            string sigBaseStringParams = "oauth_consumer_key=" + key;
+            string sigBaseStringParams = "";
+            sigBaseStringParams += "oauth_callback=http%3A%2F%2Flocal%3Fdump";
+            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);
@@ -44,6 +45,7 @@
         public static String PostData(string url, string postData)
         {
             WebClient w = new WebClient();
+            w.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
             return w.UploadString(url, postData);
         }

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Bitbucket OAuth返回“无法验证OAuth请求”。

401无法验证oauth签名和令牌(https://api.twitter.com/oauth/request_token)(Java代码)

Twitter OAuth request_token:错误代码32,无法验证

桌面应用程序仅支持oauth_callback值'oob'/ oauth / request_token

Twitter API:调用oauth request_token时,时间戳超出范围

尝试使用Oauth 1.0获取Twitter request_token时,始终显示“ 215错误的身份验证”错误

Angular中的Twitter API Request_Token

为什么ohmy-auth twitter请求不返回oauth_token?

为什么OAuth2AccessTokenSupport总是发送POST请求?

Twitter request_token端点始终返回“无法验证您的身份”

事件API的request_token方法未返回请求令牌

为什么Google OAuth2 Playground无法返回数据?

对Google OAuth 2.0使用refresh_token返回HTTP 400错误请求

为什么 GitHub Oauth2 Authorization header 的认证方案是“token”而不是“Bearer”?

为什么OAuth2客户端没有刷新过期的access_token?

为什么 angular4 调用两次 oauth/token?

OAuth还是JWT?使用哪个,为什么?

为什么客户端oauth不好?

OAuth'oauth2-token'端点返回HTML而不是JSON

为什么Google OAuth Api会刷新令牌?

数据湖上的 Polybase - 什么是 OAuth_2.0_Token_EndPoint?

为什么Microsoft Oauth2 API会更改授权请求的范围?

当我尝试使用Instagram API连接到oauth2.0时,我从api.instagram.com返回400-错误结果。为什么?

OAuth access_token请求->禁止

为什么OAuth2服务器未提供“ refresh_token”来响应“ client_credentials”授权?

OAuth 2.0上的Claim Request参数的目的是什么?

Bigcommerce API(oAuth)Webhook请求-什么是{secret_auth_password}?

为什么我无法通过PHP从Google OAuth API获取数据?

使用PHP cURL获取access_token时,Google OAuth2.0返回“ invalid_request”