From b4d768f42baaff7987697fa76555fa279c415bc4 Mon Sep 17 00:00:00 2001 From: Graham Briggs Date: Sat, 4 Jun 2016 17:08:57 -0700 Subject: [PATCH 1/2] Fixed OAuthToken in header, needs to be url encoded --- .../AsyncOAuth.ConsoleApp.csproj | 169 +++++++++--------- AsyncOAuth.ConsoleApp/ETrade.cs | 93 ++++++++++ AsyncOAuth.ConsoleApp/Program.cs | 43 ++++- AsyncOAuth/OAuthUtility.cs | 17 ++ 4 files changed, 229 insertions(+), 93 deletions(-) create mode 100644 AsyncOAuth.ConsoleApp/ETrade.cs diff --git a/AsyncOAuth.ConsoleApp/AsyncOAuth.ConsoleApp.csproj b/AsyncOAuth.ConsoleApp/AsyncOAuth.ConsoleApp.csproj index 0212139..adbaa39 100644 --- a/AsyncOAuth.ConsoleApp/AsyncOAuth.ConsoleApp.csproj +++ b/AsyncOAuth.ConsoleApp/AsyncOAuth.ConsoleApp.csproj @@ -1,91 +1,92 @@ - - - - - Debug - AnyCPU - {C8BF0013-AE03-48C0-A11B-6CF9F39257DE} - Exe - Properties - AsyncOAuth.ConsoleApp - AsyncOAuth.ConsoleApp - v4.5 - 512 - ..\ - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.dll - - - ..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.Extensions.dll - - - - - - - ..\packages\Microsoft.Net.Http.2.2.18\lib\net45\System.Net.Http.Extensions.dll - - - ..\packages\Microsoft.Net.Http.2.2.18\lib\net45\System.Net.Http.Primitives.dll - - - - - - - - - - - - - - - - - - - - - - {877842ff-edae-40e7-913b-c871ad5a48cc} - AsyncOAuth - - - - - - - - - + + + + + Debug + AnyCPU + {C8BF0013-AE03-48C0-A11B-6CF9F39257DE} + Exe + Properties + AsyncOAuth.ConsoleApp + AsyncOAuth.ConsoleApp + v4.5 + 512 + ..\ + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.dll + + + ..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.Extensions.dll + + + + + + + ..\packages\Microsoft.Net.Http.2.2.18\lib\net45\System.Net.Http.Extensions.dll + + + ..\packages\Microsoft.Net.Http.2.2.18\lib\net45\System.Net.Http.Primitives.dll + + + + + + + + + + + + + + + + + + + + + + + {877842ff-edae-40e7-913b-c871ad5a48cc} + AsyncOAuth + + + + + + + + + + --> \ No newline at end of file diff --git a/AsyncOAuth.ConsoleApp/ETrade.cs b/AsyncOAuth.ConsoleApp/ETrade.cs new file mode 100644 index 0000000..f73afa7 --- /dev/null +++ b/AsyncOAuth.ConsoleApp/ETrade.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace AsyncOAuth.ConsoleApp +{ + // a sample of ETrade client + public class ETradeClient + { + readonly string consumerKey; + readonly string consumerSecret; + readonly AccessToken accessToken; + + public ETradeClient(string consumerKey, string consumerSecret, AccessToken accessToken) + { + this.consumerKey = consumerKey; + this.consumerSecret = consumerSecret; + this.accessToken = accessToken; + } + + // sample flow for ETrade authroize + public async static Task AuthorizeSample(string consumerKey, string consumerSecret) + { + try + { + // create authorizer + var authorizer = new OAuthAuthorizer(consumerKey, consumerSecret); + + // get request token + List> args = new List>(); + args.Add(new KeyValuePair("oauth_callback", "oob")); + + var tokenResponse = await authorizer.GetRequestToken("https://etws.etrade.com/oauth/request_token",args); + var requestToken = tokenResponse.Token; + + + // var pinRequestUrl = authorizer.BuildAuthorizeUrl("https://us.etrade.com/e/t/etws/authorize", requestToken); + string pinRequestUrl = "https://us.etrade.com/e/t/etws/authorize" + "?key=" + consumerKey + "&token=" + requestToken.Key; + // open browser and get PIN Code + Process.Start(pinRequestUrl); + + // enter pin + Console.WriteLine("ENTER PIN"); + var pinCode = Console.ReadLine(); + + // get access token + + var accessTokenResponse = await authorizer.GetAccessToken("https://etws.etrade.com/oauth/access_token", requestToken, pinCode); + + // save access token. + var accessToken = accessTokenResponse.Token; + Console.WriteLine("Access Granted: "); + Console.WriteLine(" Access Key:" + accessToken.Key); + Console.WriteLine(" Access Secret:" + accessToken.Secret); + Console.WriteLine("==============================================="); + + return accessToken; + } + catch (Exception e) + { + Console.WriteLine("Exception " + e.ToString()); + } + + return null; + } + + public async Task GetQuote() + { + try + { + + + var client = OAuthUtility.CreateOAuthClient(consumerKey, consumerSecret, accessToken); + + var json = await client.GetStringAsync("https://etwssandbox.etrade.com/market/sandbox/rest/quote/GOOG,MSFT.json?detailFlag=FUNDAMENTAL"); + + return json; + } + catch (Exception e ) + { + Console.WriteLine("Exception in GetQuote: " + e.ToString()); + } + + return null; + } + + + } +} \ No newline at end of file diff --git a/AsyncOAuth.ConsoleApp/Program.cs b/AsyncOAuth.ConsoleApp/Program.cs index 1dcc786..c184293 100644 --- a/AsyncOAuth.ConsoleApp/Program.cs +++ b/AsyncOAuth.ConsoleApp/Program.cs @@ -10,28 +10,53 @@ namespace AsyncOAuth.ConsoleApp { class Program - { - // set your token - const string consumerKey = ""; - const string consumerSecret = ""; + { + // set your token + /*Dear Graham Briggs, + This message is regarding the E*TRADE API. + Your key and secret for the sandbox environment are as follows: + oauth_consumer_key: b3de705c7e73dba19ed2cd406f24ea00 + consumer_secret: 41486fa59ab14b564d294b8b18e3fcb7 */ + + const string consumerKey = "b3de705c7e73dba19ed2cd406f24ea00"; + const string consumerSecret = "41486fa59ab14b564d294b8b18e3fcb7"; static async Task Run() { // initialize computehash function OAuthUtility.ComputeHash = (key, buffer) => { using (var hmac = new HMACSHA1(key)) { return hmac.ComputeHash(buffer); } }; - // sample, twitter access flow - var accessToken = await TwitterClient.AuthorizeSample(consumerKey, consumerSecret); + // sample, ETrade access flow + Console.WriteLine("ASyncOauth ETrade Sample: "); + System.Threading.Thread.Sleep(1000); - var client = new TwitterClient(consumerKey, consumerSecret, accessToken); + Console.WriteLine("Getting access token"); + var accessToken = await ETradeClient.AuthorizeSample(consumerKey, consumerSecret); - var tl = await client.GetTimeline(10, 1); - Console.WriteLine(tl); + if ( accessToken == null ) + { + Console.WriteLine("Error getting access token"); + return; + } + + // create the client with the access token and consumer key + var client = new ETradeClient(consumerKey, consumerSecret, accessToken); + + // Get Quote: + Console.WriteLine("Getting Quotes from sandbox server: "); + + var quoteResponse = await client.GetQuote(); + + Console.WriteLine(quoteResponse); } static void Main(string[] args) { Run().Wait(); + + // Exit + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); } } } \ No newline at end of file diff --git a/AsyncOAuth/OAuthUtility.cs b/AsyncOAuth/OAuthUtility.cs index e4be4e1..ea2a6b4 100644 --- a/AsyncOAuth/OAuthUtility.cs +++ b/AsyncOAuth/OAuthUtility.cs @@ -76,10 +76,27 @@ public static IEnumerable> BuildBasicParameters(str if (token != null) parameters.Add(new KeyValuePair("oauth_token", token.Key)); if (optionalParameters == null) optionalParameters = Enumerable.Empty>(); + // generate the signature var signature = GenerateSignature(consumerSecret, new Uri(url), method, token, parameters.Concat(optionalParameters)); + // add the signature to the parameters parameters.Add(new KeyValuePair("oauth_signature", signature)); + // TODO - this is a change made to get library to work with ETrade OAuth login + // the token must be URL encoded, but if you URL encode token prior to generate signature, signature is incorrect + // this is brute force solution that worked for me, but there is probably a better way to handle this + try + { + var findToken = parameters.First(x => x.Key == "oauth_token"); + + parameters.Remove(findToken); + parameters.Add(new KeyValuePair(findToken.Key, findToken.Value.UrlEncode())); + } + catch + { + // oauth_token is not in the header, continue + } + return parameters; } From 05c848c6b67e01b0163d63fdf03265ebca58d141 Mon Sep 17 00:00:00 2001 From: Graham Briggs Date: Sat, 4 Jun 2016 17:29:31 -0700 Subject: [PATCH 2/2] removed token from program file example --- AsyncOAuth.ConsoleApp/Program.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/AsyncOAuth.ConsoleApp/Program.cs b/AsyncOAuth.ConsoleApp/Program.cs index c184293..8d0c20a 100644 --- a/AsyncOAuth.ConsoleApp/Program.cs +++ b/AsyncOAuth.ConsoleApp/Program.cs @@ -12,14 +12,10 @@ namespace AsyncOAuth.ConsoleApp class Program { // set your token - /*Dear Graham Briggs, - This message is regarding the E*TRADE API. - Your key and secret for the sandbox environment are as follows: - oauth_consumer_key: b3de705c7e73dba19ed2cd406f24ea00 - consumer_secret: 41486fa59ab14b564d294b8b18e3fcb7 */ + - const string consumerKey = "b3de705c7e73dba19ed2cd406f24ea00"; - const string consumerSecret = "41486fa59ab14b564d294b8b18e3fcb7"; + const string consumerKey = "yourConsumerKey"; + const string consumerSecret = "yourConsumerToken"; static async Task Run() {