CSC/ECE 517 Fall 2013/ch1 1w19 rj

From Expertiza_Wiki
Jump to navigation Jump to search

Using secure API authorization via OAuth

OAuth is the de facto standard authentication mechanism used by prominent websites like Facebook and Twitter. This wiki discusses Ruby support for OAuth and highlight using examples.

Introduction to OAuth

OAuth in Ruby

Ruby has several gems for turning your web application into an OAuth Provider or OAuth Consumer. The most popular, of course, is oauth. However, this is NOT a Rails plugin, but could easily be used for the foundation for such a Rails plugin. As a matter of fact it has been pulled out from an OAuth Rails Plugin which now requires this GEM [Source]. Some documentation on the oauth gem is available at it's canonical GitHub repository.

Creating a sample OAuth Application

TODO: Add Ruby/Rails version used

Creating an OAuth Provider

Following steps will create a basic Rails application that uses OAuth to authenticate the requests.
1. Create a Rails application and remove public/index.html

rails new OAuthProviderApp


2. Add devise, oauth-plugin and dynamic_form gems to your Gemfile

gem 'dynamic_form'
gem 'devise'
gem 'oauth-plugin'


3. Run bundle install to install the Gems

bundle install


4. Run the devise:install and devise User generators to generate the User model, controller and views

rails generate devise:install
rails generate devise User

The above commands generates the migration and model for User.

5. Run the oauth_provider generator

rails generate oauth_provider

This will generate the migrations, models, controllers, views and routes for the following:

  • OAuthToken or AccessToken - The token used to associate the request with the resource owner.
  • ClientApplication - Client application that needs access to the services offered by the Server on behalf of the Resource owner
  • OAuthNonce - Used for verifying requests from the client


6. Migrate the database to create tables for User, OAuthToken, ClientApplication, and OAuthNonce in the database

rake db:migrate


7. To test the application, add the following route to your config/routes.rb

root :to => 'oauth_clients#index'

Thus, the home page will display the list of OAuth clients registered by a user (developer of OAuth client).

8. Add ClientApplication and OAuthToken associations to User model (app/models/user.rb)

has_many :client_applications
has_many :tokens, :class_name => 'Oauth2Token', :order => 'authorized_at desc', :include=>[:client_application]


9. Add the following accessors to the corresponding models

attr_accessible :user, :client_application                        # Add this to AccessToken
attr_accessible :nonce, :password, :timestamp                     # Add this to OauthNonce
attr_accessible :callback_url, :client_application                # Add this to RequestToken
attr_accessible :user, :client_application, :scope                # Add this to Oauth2Token
attr_accessible :client_application, :user, :scope, :callback_url # Add this to Oauth2Verifier
attr_accessible :name, :url, :callback_url, :support_url          # Add this to ClientApplication

This is required since the generator for oauth_provider is outdated.

10. Add the following alias to app/controllers/oauth_controller.rb and app/controllers/oauth_clients_controller.rb after the class declaration

alias :login_required :authenticate_user!

This is required because oauth-plugin uses login_required method to determine whether the user is authenticated or not. In order to determine whether the user is authenticated or not, we use the authenticate_user! method provided by devise gem.

11. Add the following filter to config/application.rb

require 'oauth/rack/oauth_filter'               #Add before declaration of module OAuthProviderApp
config.middleware.use OAuth::Rack::OAuthFilter  #Add after declaration of class Application

This adds the OAuthFilter to the middleware layer and thus allows filtering out unauthorized calls.

12. Add the following method to app/controllers/application_controller.rb

def current_user=(user)
  current_user = user
end

This method is required by oauth-plugin to let devise know who the user is.

13. Generate a new controller that will define the services provided by the this provider

rails generate controller API::V1::Data


14. Add a dummy service method to this controller and have it render some response. This will be the service that the OAuth client will try to access.

class Api::V1::DataController
  respond_to :json, :xml                          
  oauthenticate :interactive=>false                # Actions in this controller can only be accessed via OAuth
  def show                                         # This is the service OAuth client will call 
    respond_with 'My birthday is on 09/05/2013'
  end
end


15. Add the following to config/routes.rb

namespace :api do
  namespace :v1 do
    match "show" => "data#show"
  end
end

Creating an OAuth Consumer

Following steps will create a basic Rails application that uses OAuth to access customer's data (birth date) from an OAuth provider.
1. Create a Rails application and remove public/index.html

rails new OAuthConsumerApp


2. Add devise and oauth-plugin gems to your Gemfile

gem 'devise'
gem 'oauth-plugin'


3. Run bundle install to install the Gems

bundle install


4. Run the devise:install and devise User generators to generate the User model, controller and views

rails generate devise:install
rails generate devise User

The above commands generates the migration and model for User.

5. Run the oauth_consumer generator

rails generate oauth_consumer user

This will generate the migrations, models, controllers and routes for ConsumerToken which is used by this Consumer to authenticate with the Provider.

6. Migrate the database to create tables for User and ConsumerToken

rake db:migrate


7. Add the following alias to app/controllers/oauth_consumers_controller.rb after the class declaration

alias :login_required :authenticate_user!

This is required because oauth-plugin uses login_required method to determine whether the user is authenticated or not. In order to determine whether the user is authenticated or not, we use the authenticate_user! method provided by devise gem.

8. Add the following method to app/controllers/application_controller.rb

def current_user=(user)
  current_user = user
end

This method is required by oauth-plugin to let devise know who the user is.

9. Create a new model that subclasses ConsumerToken for the above OAuthProvider service

class TestToken < ConsumerToken
  TEST_SETTINGS={
      :site => "http://localhost:3000",
      :request_token_path => "/oauth/request_token",
      :access_token_path => "/oauth/access_token",
      :authorize_path => "/oauth/authorize"
  }
  def self.consumer(options={})
    @consumer ||= OAuth::Consumer.new(credentials[:key], credentials[:secret], TEST_SETTINGS.merge(options))
  end
end

The purpose of this subclass is to define the consumer method that is based on the Provider.

10. Add the following to config/initializers/oauth_consumers.rb defining the Consumer key and secret provided by the OAuthProviderApp

OAUTH_CREDENTIALS={
   :test =>{
   :key => "CRcIJ15MwSqlDTxsH8MpO3En4wjaOxkqeofLioH4",
       :secret => "C7uci8xkyMShCf4SNXWPclKbBo3ml1Zf2W2XWu4W",
        :expose => true
   }
}


11. Generate a controller for testing the application

rails generate controller welcome index


12. Add logic to a controller action that performs the OAuth workflow as discussed in Introduction

def index
  @consumer_tokens = TestToken.all :conditions => {:user_id => current_user.id}
  @token = @consumer_tokens.first.client
  render inline: @token.get("/api/v1/data").body
end



13. Add the following route to config/routes.rb

root :to => 'welcome#index'