无法将DotINTEXT签名与DotNetOpenAuth ServiceProvider一起使用

时间:2012-12-20 13:08:01

标签: c# asp.net dotnetopenauth

我正在使用OAuth 1.0(a)(NuGet包DotNetOpenAuth.OAuth.ServiceProvider, version = 4.1.4.12333)构建DotNetOpenAuth授权服务器。服务器托管在ASP.NET应用程序中,但这与问题无关。

我的ServiceProvider配置如下:

private ServiceProvider GetServiceProvider()
{
    var baseUri = "http://myauth.com";
    return new ServiceProvider(
        new ServiceProviderDescription
        {
            UserAuthorizationEndpoint = new MessageReceivingEndpoint(
                new Uri(baseUri + "/get_request_token"), 
                HttpDeliveryMethods.GetRequest
            ),
            RequestTokenEndpoint = new MessageReceivingEndpoint(
                new Uri(baseUri + "/authorize"), 
                HttpDeliveryMethods.PostRequest
            ),
            AccessTokenEndpoint = new MessageReceivingEndpoint(
                new Uri(baseUri + "/get_token"), 
                HttpDeliveryMethods.PostRequest
            ),
            ProtocolVersion = ProtocolVersion.V10a,
            TamperProtectionElements = new ITamperProtectionChannelBindingElement[] 
            {
                new PlaintextSigningBindingElement(),
                new HmacSha1SigningBindingElement(),
            },
        },
        tokenManager,
        new OAuthServiceProviderMessageFactory(tokenManager)
    );
}

我的get_request_token端点的相关部分如下所示:

var serviceProvider = GetServiceProvider();
var tokenRequest = serviceProvider.ReadTokenRequest();

现在,当消费者向此端点发送以下请求时:

GET /get_request_token?oauth_nonce=C5657420BCE5F3224914304376B5334696B09B7FFC17C105A7F9629A008869DC&oauth_timestamp=1356006599&oauth_consumer_key=sampleconsumer&oauth_signature_method=plaintext&oauth_signature=samplesecret%26&oauth_version=1.0&oauth_callback=http%3a%2f%2flocalhost%3a30103%2fCustomOAuth1 HTTP/1.1

Host: localhost:8180
Connection: close

(为清楚起见):

oauth_nonce=C5657420BCE5F3224914304376B5334696B09B7FFC17C105A7F9629A008869DC
oauth_timestamp=1356006599
oauth_consumer_key=sampleconsumer
oauth_signature_method=plaintext
oauth_signature=samplesecret%26
oauth_version=1.0
oauth_callback=http%3a%2f%2flocalhost%3a30103%2fCustomOAuth1

serviceProvider.ReadTokenRequest()方法抛出异常:

The UnauthorizedTokenRequest message required protections {All} but the channel could only apply {Expiration, ReplayProtection}.
   at DotNetOpenAuth.Messaging.Channel.ProcessIncomingMessage(IProtocolMessage message)
   at DotNetOpenAuth.Messaging.Channel.ReadFromRequest(HttpRequestBase httpRequest)
   at DotNetOpenAuth.Messaging.Channel.TryReadFromRequest[TRequest](HttpRequestBase httpRequest, TRequest& request)
   at DotNetOpenAuth.OAuth.ServiceProvider.ReadTokenRequest(HttpRequestBase request)
   at DotNetOpenAuth.OAuth.ServiceProvider.ReadTokenRequest()
   at OAuthServers.OAuth1.Services.OAuth1Service.Any(GetRequestTokenRequest request)
   at lambda_method(Closure , Object , Object )
   at ServiceStack.ServiceHost.ServiceRunner`1.Execute(IRequestContext requestContext, Object instance, TRequest request)

另一方面,如果客户端发送以下请求:

GET /get_request_token?oauth_callback=http%3a%2f%2flocalhost%3a65271%2foauth1%2fHandleAccessToken&oauth_consumer_key=sampleconsumer&oauth_nonce=rGFvxlWm&oauth_signature_method=HMAC-SHA1&oauth_signature=HV%2f5Vq%2b0cF3NrtiISE9k4jmgCrY%3d&oauth_version=1.0&oauth_timestamp=1356007830 HTTP/1.1

Host: localhost:8180
Connection: close

(为清楚起见):

oauth_callback=http%3a%2f%2flocalhost%3a65271%2foauth1%2fHandleAccessToken
oauth_consumer_key=sampleconsumer
oauth_nonce=rGFvxlWm
oauth_signature_method=HMAC-SHA1
oauth_signature=HV%2f5Vq%2b0cF3NrtiISE9k4jmgCrY%3d
oauth_version=1.0
oauth_timestamp=1356007830

成功了。

正如您所看到的,这两个请求之间的唯一区别是使用了oauth_signature_method。在第一种情况下使用PLAINTEXT,而在第二种情况下使用HMAC-SHA1

是否可以使DotNetOpenAuth接受请求令牌端点的PLAINTEXT签名方法以及GET谓词(即使OAuth 1.0(a) specification建议将POST用于此端点)?是否有一些配置选项可以放松服务器上的此要求?

目前修改客户端不是我的选择。

2 个答案:

答案 0 :(得分:1)

以下代码块可以帮助您生成纯文本签名

public static string GetSignature(OAuthSignatureMethod signatureMethod,             AuthSignatureTreatment signatureTreatment, string signatureBase, string consumerSecret, string tokenSecret)
{
    if (tokenSecret.IsNullOrBlank())
    {
        tokenSecret = String.Empty;
    }

    consumerSecret = UrlEncodeRelaxed(consumerSecret);
    tokenSecret = UrlEncodeRelaxed(tokenSecret);

    string signature;
    switch (signatureMethod)
    {
        case OAuthSignatureMethod.HmacSha1:
        {
            var crypto = new HMACSHA1();
            var key = "{0}&{1}".FormatWith(consumerSecret, tokenSecret);

            crypto.Key = _encoding.GetBytes(key);
            signature = signatureBase.HashWith(crypto);

            break;
        }
        case OAuthSignatureMethod.PlainText:
        {
            signature = "{0}&{1}".FormatWith(consumerSecret, tokenSecret);

            break;
        }
        default:
            throw new NotImplementedException("Only HMAC-SHA1 is currently supported.");
        }

        var result = signatureTreatment == OAuthSignatureTreatment.Escaped
            ? UrlEncodeRelaxed(signature)
            : signature;

        return result;
    }

答案 1 :(得分:1)

OAuth身份验证分三步完成:

  1. 消费者获得未经授权的请求令牌。

  2. 用户授权请求令牌。

  3. 消费者交换访问令牌的请求令牌。
  4. 所以这就是看起来的样子:

    public class InMemoryTokenManager : IConsumerTokenManager, IOpenIdOAuthTokenManager
    {
    private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();
    
    public InMemoryTokenManager(string consumerKey, string consumerSecret)
    {
        if (String.IsNullOrEmpty(consumerKey))
        {
            throw new ArgumentNullException("consumerKey");
        }
    
        this.ConsumerKey = consumerKey;
        this.ConsumerSecret = consumerSecret;
    }
    
    public string ConsumerKey { get; private set; }
    
    public string ConsumerSecret { get; private set; }
    
    #region ITokenManager Members
    
    public string GetConsumerSecret(string consumerKey)
    {
        if (consumerKey == this.ConsumerKey)
        {
            return this.ConsumerSecret;
        }
        else
        {
            throw new ArgumentException("Unrecognized consumer key.", "consumerKey");
        }
    }
    
    public string GetTokenSecret(string token)
    {
        return this.tokensAndSecrets[token];
    }
    
    public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response)
    {
        this.tokensAndSecrets[response.Token] = response.TokenSecret;
    }
    
    public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret)
    {
        this.tokensAndSecrets.Remove(requestToken);
        this.tokensAndSecrets[accessToken] = accessTokenSecret;
    }
    
    /// <summary>
    /// Classifies a token as a request token or an access token.
    /// </summary>
    /// <param name="token">The token to classify.</param>
    /// <returns>Request or Access token, or invalid if the token is not recognized.</returns>
    public TokenType GetTokenType(string token)
    {
        throw new NotImplementedException();
    }
    
    #endregion
    
    #region IOpenIdOAuthTokenManager Members
    
    public void StoreOpenIdAuthorizedRequestToken(string consumerKey, AuthorizationApprovedResponse authorization)
    {
        this.tokensAndSecrets[authorization.RequestToken] = string.Empty;
    }
    
    #endregion
    }