Skip to content
12 changes: 12 additions & 0 deletions RestSharp.IntegrationTests/Models/LinkedINMemberProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace RestSharp.IntegrationTests.Models
{
/// <summary>
/// Model for used by the LinkedIN integration tests. <see cref="oAuth1Tests.Can_Retrieve_Member_Profile_Field_Field_Selector_From_LinkedIN"/>.
/// </summary>
public class LinkedINMemberProfile
{
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
<Compile Include="Helpers\Extensions.cs" />
<Compile Include="FileTests.cs" />
<Compile Include="Helpers\Handlers.cs" />
<Compile Include="Models\LinkedINMemberProfile.cs" />
<Compile Include="oAuth1Tests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="CompressionTests.cs" />
Expand Down
103 changes: 103 additions & 0 deletions RestSharp.IntegrationTests/oAuth1Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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\"" ) );
}
}
}
27 changes: 18 additions & 9 deletions RestSharp/Authenticators/OAuth1Authenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

namespace RestSharp.Authenticators
{
/// <seealso href="http://tools.ietf.org/html/rfc5849"/>
public class OAuth1Authenticator : IAuthenticator
{
public virtual string Realm { get; set; }
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down