diff --git a/RestSharp.IntegrationTests/Models/LinkedINMemberProfile.cs b/RestSharp.IntegrationTests/Models/LinkedINMemberProfile.cs
new file mode 100644
index 000000000..2446aed7f
--- /dev/null
+++ b/RestSharp.IntegrationTests/Models/LinkedINMemberProfile.cs
@@ -0,0 +1,12 @@
+namespace RestSharp.IntegrationTests.Models
+{
+ ///
+ /// Model for used by the LinkedIN integration tests. .
+ ///
+ public class LinkedINMemberProfile
+ {
+ public string Id { get; set; }
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj b/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj
index a0b615298..b0e8a3dfd 100644
--- a/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj
+++ b/RestSharp.IntegrationTests/RestSharp.IntegrationTests.csproj
@@ -65,6 +65,7 @@
+
diff --git a/RestSharp.IntegrationTests/oAuth1Tests.cs b/RestSharp.IntegrationTests/oAuth1Tests.cs
index d9002c680..ca734e50b 100644
--- a/RestSharp.IntegrationTests/oAuth1Tests.cs
+++ b/RestSharp.IntegrationTests/oAuth1Tests.cs
@@ -2,6 +2,7 @@
using System.Linq;
using System.Xml.Serialization;
using RestSharp.Authenticators.OAuth;
+using RestSharp.IntegrationTests.Models;
using Xunit;
using System.Net;
using RestSharp.Contrib;
@@ -186,5 +187,107 @@ public void Use_RFC_3986_Encoding_For_Auth_Signature_Base()
// assert
Assert.Equal( "%3B%2F%3F%3A%40%26%3D%2B%24%2C%21%2A%27%28%29", escapedString );
}
+
+ [Fact( Skip = "Provide your own consumer key/secret before running" )]
+ public void Can_Authenticate_LinkedIN_With_OAuth()
+ {
+ const string consumerKey = "TODO_CONSUMER_KEY_HERE";
+ const string consumerSecret = "TODO_CONSUMER_SECRET_HERE";
+
+ // request token
+ var client = new RestClient {
+ BaseUrl = "https://api.linkedin.com/uas/oauth",
+ Authenticator = OAuth1Authenticator.ForRequestToken( consumerKey, consumerSecret, "http://localhost" )
+ };
+ var requestTokenRequest = new RestRequest( "requestToken" );
+ var requestTokenResponse = client.Execute( requestTokenRequest );
+ Assert.NotNull( requestTokenResponse );
+ Assert.Equal( HttpStatusCode.OK, requestTokenResponse.StatusCode );
+ var requestTokenResponseParameters = HttpUtility.ParseQueryString( requestTokenResponse.Content );
+ var requestToken = requestTokenResponseParameters[ "oauth_token" ];
+ var requestSecret = requestTokenResponseParameters[ "oauth_token_secret" ];
+ Assert.NotNull( requestToken );
+ Assert.NotNull( requestSecret );
+
+ // redirect user
+ requestTokenRequest = new RestRequest( "authenticate?oauth_token=" + requestToken );
+ var redirectUri = client.BuildUri( requestTokenRequest );
+ Process.Start( redirectUri.ToString() );
+ var requestUrl = "TODO: put browser URL here"; // replace this via the debugger with the return url from LinkedIN. Simply copy it from the opened browser
+ if ( !Debugger.IsAttached )
+ {
+ Debugger.Launch();
+ }
+ Debugger.Break();
+
+ // get the access token
+ var requestTokenQueryParameters = HttpUtility.ParseQueryString( new Uri( requestUrl ).Query );
+ var requestVerifier = requestTokenQueryParameters[ "oauth_verifier" ];
+ client.Authenticator = OAuth1Authenticator.ForAccessToken( consumerKey, consumerSecret, requestToken, requestSecret, requestVerifier );
+ var requestAccessTokenRequest = new RestRequest( "accessToken" );
+ var requestActionTokenResponse = client.Execute( requestAccessTokenRequest );
+ Assert.NotNull( requestActionTokenResponse );
+ Assert.Equal( HttpStatusCode.OK, requestActionTokenResponse.StatusCode );
+ var requestActionTokenResponseParameters = HttpUtility.ParseQueryString( requestActionTokenResponse.Content );
+ var accessToken = requestActionTokenResponseParameters[ "oauth_token" ];
+ var accessSecret = requestActionTokenResponseParameters[ "oauth_token_secret" ];
+ Assert.NotNull( accessToken );
+ Assert.NotNull( accessSecret );
+ }
+
+ [Fact( Skip = "Provide your own consumer key/secret/accessToken/accessSecret before running. You can retrieve the access token/secret by running the LinkedIN oAuth test" )]
+ public void Can_Retrieve_Member_Profile_Field_Field_Selector_From_LinkedIN()
+ {
+ const string consumerKey = "TODO_CONSUMER_KEY_HERE";
+ const string consumerSecret = "TODO_CONSUMER_SECRET_HERE";
+ const string accessToken = "TODO_ACCES_TOKEN_HERE";
+ const string accessSecret = "TODO_ACCES_SECRET_HERE";
+
+ // arrange
+ var client = new RestClient {
+ BaseUrl = "http://api.linkedin.com/v1",
+ Authenticator = OAuth1Authenticator.ForProtectedResource( consumerKey, consumerSecret, accessToken, accessSecret )
+ };
+ var request = new RestRequest( "people/~:(id,first-name,last-name)" );
+
+ // act
+ var response = client.Execute< LinkedINMemberProfile >( request );
+
+ // assert
+ Assert.NotNull( response );
+ Assert.Equal( HttpStatusCode.OK, response.StatusCode );
+ Assert.NotNull( response.Data );
+ Assert.NotNull( response.Data.Id );
+ Assert.NotNull( response.Data.FirstName );
+ Assert.NotNull( response.Data.LastName );
+ }
+
+ [Fact( Skip = "Provide your own consumer key/secret before running" )]
+ public void Can_Query_Vimeo()
+ {
+ const string consumerKey = "TODO_CONSUMER_KEY_HERE";
+ const string consumerSecret = "TODO_CONSUMER_SECRET_HERE";
+
+ // arrange
+ var client = new RestClient {
+ BaseUrl = "http://vimeo.com/api/rest/v2",
+ Authenticator = OAuth1Authenticator.ForRequestToken( consumerKey, consumerSecret )
+ };
+ var request = new RestRequest();
+ request.AddParameter( "format", "json" );
+ request.AddParameter( "method", "vimeo.videos.search" );
+ request.AddParameter( "query", "weather" );
+ request.AddParameter( "full_response", 1 );
+
+ // act
+ var response = client.Execute( request );
+
+ // assert
+ Assert.NotNull( response );
+ Assert.Equal( HttpStatusCode.OK, response.StatusCode );
+ Assert.NotNull( response.Content );
+ Assert.False( response.Content.Contains( "\"stat\":\"fail\"" ) );
+ Assert.True( response.Content.Contains( "\"stat\":\"ok\"" ) );
+ }
}
}
diff --git a/RestSharp/Authenticators/OAuth1Authenticator.cs b/RestSharp/Authenticators/OAuth1Authenticator.cs
index a2f19f829..faac64aaa 100644
--- a/RestSharp/Authenticators/OAuth1Authenticator.cs
+++ b/RestSharp/Authenticators/OAuth1Authenticator.cs
@@ -15,6 +15,7 @@
namespace RestSharp.Authenticators
{
+ ///
public class OAuth1Authenticator : IAuthenticator
{
public virtual string Realm { get; set; }
@@ -150,19 +151,27 @@ public void Authenticate(IRestClient client, IRestRequest request)
private void AddOAuthData(IRestClient client, IRestRequest request, OAuthWorkflow workflow)
{
var url = client.BuildUri(request).ToString();
+ var queryStringStart = url.IndexOf('?');
+ if (queryStringStart != -1)
+ url = url.Substring(0, queryStringStart);
OAuthWebQueryInfo oauth;
var method = request.Method.ToString().ToUpperInvariant();
var parameters = new WebParameterCollection();
- // for non-GET style requests make sure params are part of oauth signature
- if (request.Method != Method.GET && request.Method != Method.DELETE)
+ // include all GET and POST parameters before generating the signature
+ // according to the RFC 5849 - The OAuth 1.0 Protocol
+ // http://tools.ietf.org/html/rfc5849#section-3.4.1
+ // if this change causes trouble we need to introduce a flag indicating the specific OAuth implementation level,
+ // or implement a seperate class for each OAuth version
+ foreach (var p in client.DefaultParameters.Where(p => p.Type == ParameterType.GetOrPost))
{
- foreach (var p in request.Parameters.Where(p => p.Type == ParameterType.GetOrPost))
- {
- parameters.Add(new WebPair(p.Name, p.Value.ToString()));
- }
+ parameters.Add( new WebPair( p.Name, p.Value.ToString() ) );
+ }
+ foreach (var p in request.Parameters.Where(p => p.Type == ParameterType.GetOrPost))
+ {
+ parameters.Add(new WebPair(p.Name, p.Value.ToString()));
}
switch (Type)
@@ -193,10 +202,10 @@ private void AddOAuthData(IRestClient client, IRestRequest request, OAuthWorkflo
request.AddHeader("Authorization", GetAuthorizationHeader(parameters));
break;
case OAuthParameterHandling.UrlOrPostParameters:
- parameters.Add("oauth_signature", HttpUtility.UrlDecode(oauth.Signature));
- foreach (var parameter in parameters)
+ parameters.Add("oauth_signature", oauth.Signature);
+ foreach (var parameter in parameters.Where(parameter => !parameter.Name.IsNullOrBlank() && parameter.Name.StartsWith("oauth_")))
{
- request.AddParameter(parameter.Name, parameter.Value);
+ request.AddParameter(parameter.Name, HttpUtility.UrlDecode(parameter.Value));
}
break;
default: