Tuesday, May 2, 2017

Moving to Medium

Hello,

I'm picking up blogging again. Not here though. If you follow me, I am at https://medium.com/@ervib

Wednesday, December 5, 2012

Ruby on Rails - RSpec Tutorial

Hello,

It seems that there isn't a lot of RSpec tutorial that's clear out there.
Let's see if I can write one that's clear.

Assuming that you already have a Ruby on Rails app and are trying to add unit test to your app using RSpec:

  1. Add "gem 'rspec'" to your Gemfile
  2. Run ".../project$ bundle install"
  3. After the RSpec gem is installed, run ".../project$ rails generate rspec:install"
You will see that a "spec" folder is created inside your project folder:
project/
  app/
  config/
  Gemfile
  ...
  spec/

Inside the "spec" folder, you have a "spec_helper.rb" file.
That helper file makes sure that all necessary files under test are loaded.
It contains the following:

# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

RSpec.configure do |config|
  # ## Mock Framework
  #
  # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
  #
  # config.mock_with :mocha
  # config.mock_with :flexmock
  # config.mock_with :rr

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = true

  # If true, the base class of anonymous controllers will be inferred
  # automatically. This will be the default behavior in future versions of
  # rspec-rails.
  config.infer_base_class_for_anonymous_controllers = false

  # Run specs in random order to surface order dependencies. If you find an
  # order dependency and want to debug it, you can fix the order by providing
  # the seed, which is printed after each run.
  #     --seed 1234
  config.order = "random"
end

As you can see, the environment is set to "test." You can change it if you would like. 
Also, bolded lines in blue above are not commented out by default. If you do not use a relational DB (like me, I use MongoDB), feel free to comment them out.

Create the "controllers," "models," and "views" folders inside the "spec" folder:
spec/
  controllers/
  models/
  views/

Let's say you would like to create a test file for one of your controllers, posts_controller.rb, go into the "spec/controllers" folder, create a file called "posts_controller_spec.rb." Make sure that "_spec" is on the file name because that's how RSpec identifies its test files.
Assuming that you have an action called show within your posts_controller.rb, open up the "post_controller_spec.rb" and add the following:

#The spec_helper makes sure that we load all necessary files in.
require 'spec_helper'

#Test the PostsController
describe PostsController do
  #Test the show action
  describe 'show' do
    it "returns all posts" do
      get :show 
      response.should_not be_nil
    end
  end
end
      
Save the file.
Go out to your project directory and run ".../project$ rake spec"
The "rake spec" command is to run all unit tests within your "spec" folder.
To run the unit test in an individual file, execute ".../project$ rspec spec/controllers/posts_controller_spec.rb"

That's all there is to it. Hope I was being clear.
Please feel free to leave a comment if I am not.

LinkedIn REST URL (Step 3 - Obtain Access Token)

Hello again,

My last post was Step 2 for obtaining authorization http://dailyprogrammingtalk.blogspot.com/2012/11/linkedin-rest-url-step-2-obtain.html

We will go through the final step of OAuth, that is obtaining an access token, so we can make API calls.
Using the new OAuth token and verfier we obtained from Step 2, make a POST request to:

https://api.linkedin.com/uas/oauth/requestToken

You might notice that the path of the URL is the same as the one we used in Step 1. There's no typo. Don't worry :)

To make the POST request, you can still use the same code in Step 1, but you need to pass in the OAuth token, verifier, and token secret from Step 2:

OAuthBase oauth = new OAuthBase();
string linkedinUrl = "https://api.linkedin.com/uas/oauth/requestToken"
string url = String.Empty;
string urlParameters = String.Empty;
string timeStamp = oauth.GenerateTimeStamp();
string nonce = oauth.GenerateNonce();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(linkedinUrl);
request.Method = "POST";
string signature = oauth.GenerateSignature(new Uri(linkedinUrl), consumerKey, consumerSecret, step2Tokenstep2TokenSecret, "POST", timeStamp, nonce, out url, out urlParameters);

But then, for the OAuth library I am using, the GenerateSignature method does not accept verifier in the arguments. In case you are curious which OAuth library I use, it's from http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs
So, I need to make modifications to the GenerateSignatureBase method to accept verifier in the arguments and add the verifier to the list of QueryParameter like below:

public string GenerateSignatureBase(Uri url, string consumerKey, string token, string tokenSecret, string httpMethod, string timeStamp, string verifierstring nonce, string signatureType, out string normalizedUrl, out string normalizedRequestParameters)
{
  ...
  List<QueryParameter> parameters = GetQueryParameters(url.Query);
  ...

  if (!String.IsNullOrEmpty(verifier))
  {
    parameters.Add(new QueryParameter("oauth_verifier", verifier));
  }
  ...
}

After making the changes above, add the extra "verifier" argument to the GenerateSignature methods that make a call to the GenerateSignatureBase method.
After that, you can pass in the verifier value:

string signature = oauth.GenerateSignature(new Uri(linkedinUrl), consumerKey, consumerSecret, step2Tokenstep2TokenSecret, "POST", timeStamp, step2Verifier, nonce, out url, out urlParameters);

Next is your authorization header needs to contain the OAuth token and verifier from Step 2:

StringBuilder header = new StringBuilder("OAuth ");
header.AppendFormat("oauth_consumer_key=\"{0}\"", consumerKey);
header.AppendFormat(", oauth_signature_method=\"{0}\"""HMAC-SHA1");
header.AppendFormat(", oauth_signature=\"{0}\"", MsSecurity.Encoder.UrlEncode(signature));
header.AppendFormat(", oauth_nonce=\"{0}\"", nonce);
header.AppendFormat(", oauth_timestamp=\"{0}\"", timeStamp);
header.AppendFormat(", oauth_version=\"{0}\"""1.0");
header.AppendFormat(", oauth_token=\"{0}\"", step2Token);
header.AppendFormat(", oauth_verifier=\"{0}\"", step2Verifier);

Make the POST request and you will receive the access token and token secret in the response:
oauth_token=efgh&oauth_token_secret=def456

From now on, you can forget about everything you stored from Step 1 and 2. The values of oauth_token and oauth_token_secret from Step 3 are the only ones you need to save because you use them in every API call you make.

Parse them out:

string step3Token = Regex.Match(token, @"oauth_token=([^&]+)").Groups[1].Value,
string step3TokenSecret = Regex.Match(token, @"oauth_token_secret=([^&]+)").Groups[1].Value

Now, to test if your oauth_token and oauth_token secret values work, make a GET request to:

http://api.linkedin.com/v1/people

For the signature and authorization header, do the following:

string signature = oauth.GenerateSignature(new Uri(linkedinUrl), consumerKey, consumerSecret, step3Tokenstep3TokenSecret, "POST", timeStamp, nonce, out url, out urlParameters);

StringBuilder header = new StringBuilder("OAuth ");
header.AppendFormat("oauth_consumer_key=\"{0}\"", consumerKey);
header.AppendFormat(", oauth_signature_method=\"{0}\"""HMAC-SHA1");
header.AppendFormat(", oauth_signature=\"{0}\"", MsSecurity.Encoder.UrlEncode(signature));
header.AppendFormat(", oauth_nonce=\"{0}\"", nonce);
header.AppendFormat(", oauth_timestamp=\"{0}\"", timeStamp);
header.AppendFormat(", oauth_version=\"{0}\"""1.0");
header.AppendFormat(", oauth_token=\"{0}\"", step3Token);

Notice that the verifier is no longer needed.
So, after making the GET request, you will see a response similar to:

<?xml version= "1.0" encoding="UTF-8" standalone="yes"?>
<person>
  <first-name>Kirsten</first-name>  
  <last-name>Jones</last-name>
  <headline>Developer Advocate at LinkedIn</headline>
  <site-standard-profile-request>    
    <url>http://www.linkedin.com/profile?viewProfile=&amp;key=3639896&amp;authToken=JdAa&amp;authType=name&amp;trk=api*a119686*s128146*</url>
  </site-standard-profile-request>
</person>

That's all there is to it for OAuth authentication.
Please feel free to leave comments.

Wednesday, November 28, 2012

LinkedIn REST URL (Step 2 - Obtain Authorization)

Hello again,

I wrote about how to obtain a request token for LinkedIn yesterday.
For those of you who would like to read it can view it at http://dailyprogrammingtalk.blogspot.com/2012/11/linkedin-rest-url-step-1-obtain-request.html

That was just step 1 of OAuth authentication.
Step 2 is simpler. After making a POST request to obtain a request token, we will receive a response similar to below:
oauth_token=abcd&oauth_token_secret=abc123&oauth_callback_confirmed=true&xoauth_request_auth_url=https%3A%2F%2Fapi.linkedin.com%2Fuas%2Foauth%2Fauthorize&oauth_expires_in=599

Parse the querystring:
string token = Regex.Match(token, @"oauth_token=([^&]+)").Groups[1].Value,
string tokenSecret = Regex.Match(token, @"oauth_token_secret=([^&]+)").Groups[1].Value


After getting the token and token secret, append the request token in the querystring and redirect users to:
https://api.linkedin.com/uas/oauth/authenticate?oauth_token=abcd

At this point, users will choose to allow us to access their LinkedIn info or not. If yes, users will be redirected to our callback url (this callback url was set up when we obtained our consumer key on developer.linkedin.com) similar to below:

http://localhost:12345/linkedincallback.aspx?oauth_token=abcd&oauth_verifier=94262

On the callback page, parse and store the values for oauth_token, oauth_verifier, and oauth_token_secret because we need those for step 3 of OAuth authentication.

Let's move on to Step 3: http://dailyprogrammingtalk.blogspot.com/2012/12/linkedin-rest-url-step-3-obtain-access.html

Tuesday, November 27, 2012

LinkedIn REST URL (Step 1 - Obtain Request Token)

Hello,

I have had the pleasure to deal with the LinkedIn REST URLs these past few days.
There are some Ruby, Python, etc wrappers, but there is none for .NET.
There's not a lot of examples in .NET either.
So, I decided to write my own wrapper with the help of OAuthBase.cs.

Now, the basic authentication was already documented on https://developer.linkedin.com/documents/authentication.
There are 3 steps to be authenticated by LinkedIn:

  1. Obtain a request token
  2. Let users authorize our access to their info (http://dailyprogrammingtalk.blogspot.com/2012/11/linkedin-rest-api-step-2-obtain.html)
  3. Obtain an access token
I will focus on getting a request token on this blog post.

One thing that's not clear is having 'scope' in the querystring parameters.
I kept getting the signature_invalid 401 error.
It says on the documentation that we only need to make a POST request to https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile+r_emailaddress, which is misleading. I have to use a space instead of the plus sign.

So, I made a POST request to 
https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile r_emailaddress

I generated a signature using the url above, but without a token and token secret.

OAuthBase oauth = new OAuthBase();
string linkedinUrl = "https://api.linkedin.com/uas/oauth/requestToken?scope=r_basicprofile r_emailaddress"
string url = String.Empty;
string urlParameters = String.Empty;
string timeStamp = oauth.GenerateTimeStamp();
string nonce = oauth.GenerateNonce();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(linkedinUrl);
request.Method = "POST";
string signature = oauth.GenerateSignature(new Uri(linkedinUrl), consumerKey, consumerSecret, String.Empty, String.Empty, "POST", timeStamp, nonce, out url, out urlParameters);


Then, I created an 'Authorization' header for the request, which contains:

StringBuilder header = new StringBuilder("OAuth ");
header.AppendFormat("oauth_consumer_key=\"{0}\"", consumerKey);
header.AppendFormat(", oauth_signature_method=\"{0}\"""HMAC-SHA1");
header.AppendFormat(", oauth_signature=\"{0}\"", MsSecurity.Encoder.UrlEncode(signature));
header.AppendFormat(", oauth_nonce=\"{0}\"", nonce);
header.AppendFormat(", oauth_timestamp=\"{0}\"", timeStamp);
header.AppendFormat(", oauth_version=\"{0}\"""1.0");


The MsSecurity is an alias for the AntiXss library. I need to url-encode the signature. Otherwise, it won't work.

Now, I no longer get the 401 error. Hope this helps someone obtain their request token on LinkedIn.

Let's move on to Step 2: http://dailyprogrammingtalk.blogspot.com/2012/11/linkedin-rest-url-step-2-obtain.html