CSC/ECE 517 Spring 2015/ch1b 21 QW

From Expertiza_Wiki
Revision as of 02:11, 17 February 2015 by Yshang3 (talk | contribs)
Jump to navigation Jump to search

Omniauth

Omniauth is a Ruby authentication framework aimed to integrated with various types of authentication providers. It can be hooked up to any system, from social network to enterprise systems to simple username and password authentication<ref>https://github.com/intridea/omniauth/wiki</ref>.

The topic writeup for this page can be found here.

Background

With web application booming, most users login hundreds of services every day and won't expect to create unique login and password for each service. So intridea recently releases a standard library to provide multi-provider authentication for web applications. Each developer can create strategies released from different providers for OmniAuth. Each strategy is a Rack Middleware.

Rack Middleware

Rack provides a standard interface for developing web applications supporting Ruby and Ruby framework. And Rack middleware is a way to filter a request and response coming into your application<ref>http://railscasts.com/episodes/151-rack-middleware</ref>. Rack has quite simple architecture:

  • an object that responds to the call method.
  • taking the environment hash as a parameter.
  • and returning an Array with three elements: status code, environment hash and response body.
    We can install Rack with following command:
    $ gem install rack

    Then we're going to create a Rack configuration file with extension .ru in your Rails application's root directory. That instructs Rack::Builder what middleware should it use and in which order. Or to say how to combine various internal and external middlewares to form a complete Rails Rack application<ref>http://guides.rubyonrails.org/rails_on_rack.html</ref>. Rack::Builder is Rails equivalent of ActionDispatch::MiddlewareStack.

    #Rails.root/config.ru
    require 'rack'
    

    To use rackup to started up your created app, you can put the following code inside config.ru<ref>http://guides.rubyonrails.org/rails_on_rack.html</ref>. And then run rackup command:

    require ::File.expand_path('../config/environment', __FILE__)
     
    use Rails::Rack::Debugger
    use Rack::ContentLength
    run Rails.application
    
    $ rackup config.ru

    Creating a Middleware filter is just creating a Ruby class. There is an example:

    # ResponseTimer.rb
    class ResponseTimer
      def initialize(app)
        @app = app       
      end                
    
      def call(env)      
        @app.call(env)   
      end                
    end                  
    

    Sinatra

    Getting Start

    Each OmniAuth strategy is a Rack Middleware, which means it can be used the same way as other Rack middleware. Here we introduce some simple steps to illustrate how to use Twitter strategy for OmniAuth.<ref>https://github.com/intridea/omniauth</ref>

    Installing

    First start by adding this gem to your Gemfile:

    gem 'omniauth-twitter'

    If you need to use the latest HEAD version, you can do so with:

    gem 'omniauth-twitter', :github => 'arunagw/omniauth-twitter'

    Usage

    Because OmniAuth is built for multi-provider authentication, you need to build multiple strategies. For this, the Rack middleware OmniAuth::Builder class gives an easy way to build up your list of OmniAuth strategies for use in your application.

    Below is an example that you can put into a Rails initializer at config/initializers/omniauth.rb or add it to your middleware:

    Rails.application.config.middleware.use OmniAuth::Builder do
      provider :developer unless Rails.env.production?
      provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
    end
    

    Where "TWITTER_KEY" and "TWITTER_SECRET" is the appropriate values you obtained here.

    Integrating OmniAuth into Rails Application

    OmniAuth is a library extremely easy to use. It is designed to be a black box that you can send your application's users into when you need authentication and then get information back. OmniAuth was intentionally built not to automatically associate with a User model or make assumptions about how many authentication methods you might want to use or what you might want to do with the data once a user has authenticated. To use OmniAuth, you need only to redirect users to /auth/:provider , where :provider is the name of the strategy (for example, developer or twitter ). From there, OmniAuth will take over and take the user through the necessary steps to authenticate them with the chosen strategy.

    Once the user has authenticated, OmniAuth simply sets a special hash called the Authentication Hash on the Rack environment of a request to /auth/:provider/callback. This hash contains as much information about the user as OmniAuth was able to glean from the utilized strategy. You should set up an endpoint in your application that matches to the callback URL and then performs whatever steps are necessary for your application.

    For example, in a Rails app you can add a line in routes.rb file like this:

    get '/auth/:provider/callback', to: 'sessions#create'

    And in Sinatra, a callback might look something like this:

    # Support both GET and POST for callbacks
    %w(get post).each do |method|
      send(method, "/auth/:provider/callback") do
        env['omniauth.auth'] # => OmniAuth::AuthHash
      end
    end

    Also of note, by default, if user authentication fails on the provider side, OmniAuth will catch the response and then redirect the request to the path /auth/failure, passing a corresponding error message in a parameter named message. You may want to add an action to catch these cases. Continuing with the previous Sinatra example, you could add an action like this:

    get '/auth/failure' do
      flash[:notice] = params[:message] # if using sinatra-flash or rack-flash
      redirect '/'
    end

    And finally you can have SessionsController with code that looks something like this:

    class SessionsController < ApplicationController
      def create
        @user = User.find_or_create_from_auth_hash(auth_hash)
        self.current_user = @user
        redirect_to '/'
      end
    
      protected
    
      def auth_hash
        request.env['omniauth.auth']
      end
    end

    The omniauth.auth key in the environment hash gives the Authentication Hash which will contain information about the just authenticated user including a unique id, the strategy they just used for authentication, and personal details such as name and email address as available.

    Note that OmniAuth does not perform any actions beyond setting some environment information on the callback request. It is entirely up to you how you want to implement the particulars of your application's authentication flow.

    Logging

    OmniAuth supports a configurable logger. By default, OmniAuth will log to STDOUT but you can configure this using OmniAuth.config.logger:

    # Rails application example
    OmniAuth.config.logger = Rails.logger

    Other Examples

    OmniAuth Facebook

    Installing

    To use Facebook OmniAuth Strateges<ref>https://github.com/mkdynamic/omniauth-facebook</ref>, first, add this gem into your Gemfile, and then run bundle install:

    gem 'omniauth-facebook'

    Usage

    Adding the middleware to a Rails app in config/initializers/omniauth.rb:

    Rails.application.config.middleware.use OmniAuth::Builder do
      provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
    end

    Configuring

    Option name Default Explanation
    scope email A comma-separated list of permissions you want to request from the user. See the Facebook docs for a full list of available permissions
    display page The display context to show the authentication page. Options are: page, popup and touch. Read the Facebook docs for more details
    image_size square Set the size for the returned image url in the auth hash. Valid options include square (50x50), small (50 pixels wide, variable height), normal (100 pixels wide, variable height), or large (about 200 pixels wide, variable height). Additionally, you can request a picture of a specific size by setting this option to a hash with :width and :height as keys. This will return an available profile picture closest to the requested size and requested aspect ratio. If only :width or :height is specified, we will return a picture whose width or height is closest to the requested size, respectively.
    info_fields Specify exactly which fields should be returned when getting the user's info. Value should be a comma-separated string as per <ref>https://developers.facebook.com/docs/graph-api/reference/user/</ref>
    locale Specify locale which should be used when getting the user's info. Value should be locale string as per <ref>https://developers.facebook.com/docs/reference/api/locale/</ref>
    auth_type Optionally specifies the requested authentication features as a comma-separated list <ref>https://developers.facebook.com/docs/facebook-login/reauthentication/</ref>. Valid values are https (checks for the presence of the secure cookie and asks for re-authentication if it is not present), and reauthenticate (asks the user to re-authenticate unconditionally). Default is nil.
    secure_image_url false Set to true to use https for the avatar image url returned in the auth hash
    callback_url /

    callback_path

    Specify a custom callback URL used during the server-side flow. Note this must be allowed by your app configuration on Facebook

    For example, to request email, user_birthday and read_stream permissions:

    Rails.application.config.middleware.use OmniAuth::Builder do
      provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'],
               :scope => 'email,user_birthday,read_stream'
    end

    OmniAuth GitHub

    Install

    To use GitHub OmniAuth Strateges<ref>https://github.com/intridea/omniauth-github</ref>, first, add this gem into your Gemfile, and then run bundle install:

    gem 'omniauth-github'

    Usage

    Adding the middleware to a Rails app in config/initializers/omniauth.rb:

    Rails.application.config.middleware.use OmniAuth::Builder do
      provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET']
    end

    Scopes

    GitHub API v3 lets you set scopes to provide granular access to different types of data:

    use OmniAuth::Builder do
      provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: "user,repo,gist"
    end

    More info is shown below:

    Name Description
    (no scope) Grants read-only access to public information (includes public user profile info, public repository info, and gists)
    user Grants read/write access to profile info only. Note that this scope includes user:email and user:follow
    user:email Grants read access to a user’s email addresses
    user:follow Grants access to follow or unfollow other users
    public_repo Grants read/write access to code, commit statuses, and deployment statuses for public repositories and organizations
    repo Grants read/write access to code, commit statuses, and deployment statuses for public and private repositories and organizations
    repo_deployment Grants access to deployment statuses for public and private repositories. This scope is only necessary to grant other users or services access to deployment statuses, without granting access to the code
    repo:status Grants read/write access to public and private repository commit statuses. This scope is only necessary to grant other users or services access to private repository commit statuses without granting access to the code
    delete_repo Grants access to delete adminable repositories
    notifications Grants read access to a user’s notifications. repo also provides this access
    gist Grants write access to gists
    read:repo_hook Grants read and ping access to hooks in public or private repositories
    write:repo_hook Grants read, write, and ping access to hooks in public or private repositories
    admin:repo_hook Grants read, write, ping, and delete access to hooks in public or private repositories
    admin:org_hook Grants read, write, ping, and delete access to organization hooks. Note: OAuth tokens will only be able to perform these actions on organization hooks which were created by the OAuth application. Personal access tokens will only be able to perform these actions on organization hooks created by a user
    read:org Read-only access to organization, teams, and membership
    write:org Publicize and unpublicize organization membership
    admin:org Fully manage organization, teams, and memberships
    read:public_key List and view details for public keys
    write:public_key Create, list, and view details for public keys
    admin:public_key Fully manage public keys

    References

    <references/>