Beispiel #1
0
        /// <summary>
        /// Collects and removes all query string parameters beginning with "oauth_" from the specified request,
        /// and returns them as a collection.
        /// </summary>
        /// <param name="request">The request whose query string should be searched for "oauth_" parameters.</param>
        /// <returns>The collection of parameters that were removed from the query string.</returns>
        private static NameValueCollection ExtractOAuthParametersFromQueryString(HttpRequestMessage request)
        {
            Requires.NotNull(request, "request");

            var extracted = new NameValueCollection();

            if (!string.IsNullOrEmpty(request.RequestUri.Query))
            {
                var queryString = PortableUtilities.ParseQueryString(request.RequestUri);
                foreach (var pair in queryString.AsKeyValuePairs())
                {
                    if (pair.Key.StartsWith(ParameterPrefix, StringComparison.Ordinal))
                    {
                        extracted.Add(pair.Key, pair.Value);
                    }
                }

                if (extracted.Count > 0)
                {
                    foreach (string key in extracted)
                    {
                        queryString.Remove(key);
                    }

                    var modifiedRequestUri = new UriBuilder(request.RequestUri);
                    modifiedRequestUri.Query = PortableUtilities.CreateQueryString(queryString.AsKeyValuePairs());
                    request.RequestUri       = modifiedRequestUri.Uri;
                }
            }

            return(extracted);
        }
        /// <summary>
        /// Finalizes authorization after the user has completed the authorization steps
        /// at the user agent.
        /// </summary>
        /// <param name="callbackUri">The final URL that the service provider redirected back to to signal that authorization is complete.</param>
        /// <param name="cancellationToken">A token that may be canceled to abort.</param>
        /// <returns>
        /// A task that completes when the authorization has been finalized.
        /// The access token and token secret obtained from the authorization are then
        /// available in the <see cref="AccessToken"/> and <see cref="AccessTokenSecret"/> properties.
        /// </returns>
        public async Task CompleteAuthorizationAsync(Uri callbackUri, CancellationToken cancellationToken = default(CancellationToken))
        {
            Requires.NotNull(callbackUri, "callbackUri");
            Verify.Operation(!string.IsNullOrEmpty(this.TemporaryToken), "TemporaryToken and TemporaryTokenSecret properties must be initialized first.");

            var redirectArgs = PortableUtilities.ParseQueryString(callbackUri);

            ProtocolException.ThrowIfNot(string.Equals(this.TemporaryToken, redirectArgs["oauth_token"], StringComparison.Ordinal), "oauth_token was not the expected value of \"{0}\".", this.TemporaryToken);
            string verifier = redirectArgs["oauth_verifier"];

            var handler = this.CreateOAuthMessageHandler();

            handler.AccessToken       = this.TemporaryToken;
            handler.AccessTokenSecret = this.TemporarySecret;

            using (var httpClient = new HttpClient(handler)) {
                var accessTokenEndpointBuilder = new UriBuilder(this.AccessTokenEndpoint);
                accessTokenEndpointBuilder.AppendQueryArgument("oauth_verifier", verifier);
                var response = await httpClient.PostAsync(accessTokenEndpointBuilder.Uri, new ByteArrayContent(new byte[0]), cancellationToken);

                ProtocolException.ThrowIf(response.Content == null, "Missing response entity from access token endpoint.");
                var urlEncodedArgsResponse = await response.Content.ReadAsStringAsync();

                var argsResponse = PortableUtilities.ParseUrlEncodedString(urlEncodedArgsResponse);
                response.EnsureSuccessStatusCode();
                this.AccessToken       = argsResponse["oauth_token"];
                this.AccessTokenSecret = argsResponse["oauth_token_secret"];

                this.TemporaryToken  = null;
                this.TemporarySecret = null;
            }
        }
        /// <summary>
        /// Obtains temporary credentials and a start URL to direct the user to
        /// in order to authorize the consumer to access the user's resources.
        /// </summary>
        /// <param name="callbackUri">
        /// The URL the service provider should redirect the user agent to after authorization. This becomes the value of the oauth_callback parameter.
        /// May be "oob" to indicate an out-of-band configuration.
        /// </param>
        /// <param name="cancellationToken">A token that may be canceled to abort.</param>
        /// <returns>A task whose result will be the authorization URL.</returns>
        /// <remarks>
        /// This method sets the <see cref="TemporaryToken"/> and <see cref="TemporarySecret"/>
        /// properties. These values should be preserved (or restored) till the
        /// <see cref="CompleteAuthorizationAsync(string, CancellationToken)"/> method is called.
        /// </remarks>
        public async Task <Uri> StartAuthorizationAsync(string callbackUri, CancellationToken cancellationToken = default(CancellationToken))
        {
            Requires.NotNullOrEmpty(callbackUri, "callbackUri");
            Verify.Operation(this.TemporaryCredentialsEndpoint != null, "TemporaryCredentialsEndpoint must be set first.");
            Verify.Operation(this.ConsumerKey != null, "ConsumerKey must be initialized first.");
            Verify.Operation(this.ConsumerSecret != null, "ConsumerSecret must be initialized first.");

            var authorizingHandler = this.CreateOAuthMessageHandler();

            authorizingHandler.AccessToken       = string.Empty;
            authorizingHandler.AccessTokenSecret = string.Empty;
            using (var httpClient = new HttpClient(authorizingHandler)) {
                var requestUri = new UriBuilder(this.TemporaryCredentialsEndpoint);
                requestUri.AppendQueryArgument("oauth_callback", callbackUri);

                var response = await httpClient.PostAsync(requestUri.Uri, new ByteArrayContent(new byte[0]), cancellationToken);

                ProtocolException.ThrowIf(response.Content == null, "Response missing the expected body.");
                var urlEncodedArgsResponse = await response.Content.ReadAsStringAsync();

                var argsResponse = PortableUtilities.ParseUrlEncodedString(urlEncodedArgsResponse);
                response.EnsureSuccessStatusCode();
                ProtocolException.ThrowIfNot("true" == argsResponse["oauth_callback_confirmed"], "oauth_callback_confirmed parameter not provided or does not match the expected \"true\" value in response from service provider.");
                this.TemporaryToken = argsResponse["oauth_token"];
                ProtocolException.ThrowIf(string.IsNullOrEmpty(this.TemporaryToken), "Unexpected empty or missing oauth_token parameter in response from service provider.");
                this.TemporarySecret = argsResponse["oauth_token_secret"];

                var authorizationBuilder = new UriBuilder(this.AuthorizationEndpoint);
                authorizationBuilder.AppendQueryArgument("oauth_token", this.TemporaryToken);
                return(authorizationBuilder.Uri);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Gets a normalized string of the query string parameters included in the request and the additional OAuth parameters.
        /// </summary>
        /// <param name="request">The HTTP request.</param>
        /// <param name="oauthParameters">The oauth parameters that will be added to the request.</param>
        /// <returns>The normalized string of parameters to included in the signature base string.</returns>
        private string GetNormalizedParameters(HttpRequestMessage request, NameValueCollection oauthParameters)
        {
            Requires.NotNull(request, "request");
            Requires.NotNull(oauthParameters, "oauthParameters");

            NameValueCollection nvc;

            if (request.RequestUri.Query != null)
            {
                // NameValueCollection does support non-unique keys, as long as you use it carefully.
                nvc = PortableUtilities.ParseQueryString(request.RequestUri);
            }
            else
            {
                nvc = new NameValueCollection(8);
            }

            // Add OAuth parameters.
            nvc.Add(oauthParameters);

            // Now convert the NameValueCollection into an ordered list, and properly escape all keys and value while we're at it.
            var list = new List <KeyValuePair <string, string> >(nvc.Count);

            foreach (var pair in nvc.AsKeyValuePairs())
            {
                string escapedKey   = UrlEscape(pair.Key);
                string escapedValue = UrlEscape(pair.Value ?? string.Empty);                 // value can be null if no "=" appears in the query string for this key.
                list.Add(new KeyValuePair <string, string>(escapedKey, escapedValue));
            }

            // Sort the parameters
            list.Sort((kv1, kv2) => {
                int compare = string.Compare(kv1.Key, kv2.Key, StringComparison.Ordinal);
                if (compare != 0)
                {
                    return(compare);
                }

                return(string.Compare(kv1.Value, kv2.Value, StringComparison.Ordinal));
            });

            // Convert this sorted list into a single concatenated string.
            var normalizedParameterString = new StringBuilder();

            foreach (var pair in list)
            {
                if (normalizedParameterString.Length > 0)
                {
                    normalizedParameterString.Append("&");
                }

                normalizedParameterString.Append(pair.Key);
                normalizedParameterString.Append("=");
                normalizedParameterString.Append(pair.Value);
            }

            return(normalizedParameterString.ToString());
        }
Beispiel #5
0
 /// <summary>
 /// Generates a string of random characters for use as a nonce.
 /// </summary>
 /// <returns>The nonce string.</returns>
 private string GenerateUniqueFragment()
 {
     return(PortableUtilities.GetRandomString(this.NonceLength, AllowedCharacters));
 }
Beispiel #6
0
 /// <summary>
 /// Escapes a value for transport in a URI, per RFC 3986.
 /// </summary>
 /// <param name="value">The value to escape. Null and empty strings are OK.</param>
 /// <returns>The escaped value. Never null.</returns>
 protected static string UrlEscape(string value)
 {
     return(PortableUtilities.EscapeUriDataStringRfc3986(value ?? string.Empty));
 }
Beispiel #7
0
        /// <summary>
        /// Applies OAuth authorization to the specified request.
        /// This method is applied automatically to outbound requests that use this message handler instance.
        /// However this method may be useful for obtaining the OAuth 1.0 signature without actually sending the request.
        /// </summary>
        /// <param name="request">The request.</param>
        public void ApplyAuthorization(HttpRequestMessage request)
        {
            Requires.NotNull(request, "request");
            Verify.Operation(this.ConsumerKey != null, "Not yet initialized.");
            Verify.Operation(this.ConsumerSecret != null, "Not yet initialized.");

            var    oauthParameters = this.GetOAuthParameters();
            string signature       = this.GetSignature(request, oauthParameters);

            oauthParameters.Add("oauth_signature", signature);

            // Add parameters and signature to request.
            switch (this.ParametersLocation)
            {
            case OAuthParametersLocation.AuthorizationHttpHeader:
                // Some oauth parameters may have been put in the query string of the original message.
                // We want to move any that we find into the authorization header.
                oauthParameters.Add(ExtractOAuthParametersFromQueryString(request));

                request.Headers.Authorization = new AuthenticationHeaderValue(AuthorizationHeaderScheme, PortableUtilities.AssembleAuthorizationHeader(oauthParameters.AsKeyValuePairs()));
                break;

            case OAuthParametersLocation.QueryString:
                var uriBuilder = new UriBuilder(request.RequestUri);
                uriBuilder.AppendQueryArgs(oauthParameters.AsKeyValuePairs());
                request.RequestUri = uriBuilder.Uri;
                break;
            }
        }