lasso 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +90 -2
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/lasso.gemspec +26 -4
- data/lib/lasso.rb +26 -0
- data/lib/lasso/controller/base.rb +14 -0
- data/lib/lasso/controller/instance.rb +58 -0
- data/lib/lasso/controller/settings.rb +7 -0
- data/lib/lasso/model/base.rb +23 -0
- data/lib/lasso/model/instance.rb +12 -0
- data/lib/lasso/model/oauth_one.rb +38 -0
- data/lib/lasso/model/oauth_two.rb +19 -0
- data/lib/lasso/model/settings.rb +29 -0
- data/spec/controllers.rb +26 -0
- data/spec/db/database.yml +3 -0
- data/spec/db/models.rb +45 -0
- data/spec/db/schema.rb +12 -0
- data/spec/db/test.sqlite3 +0 -0
- data/spec/lasso_spec.rb +137 -3
- data/spec/spec_helper.rb +18 -0
- metadata +46 -4
    
        data/README.rdoc
    CHANGED
    
    | @@ -1,6 +1,94 @@ | |
| 1 | 
            -
            =  | 
| 1 | 
            +
            = Lasso
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            == Identity herding with OAuth
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Lasso makes it damn easy to add SSO to your Rails application. Just load in your configuration, add a couple associations, and you are set to hit the trail running, partner.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            == Gettings started
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            I haven't made generators for anything but that's ok cause Lasso mostly works via decorators.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Lasso creates OAuth tokens via nested attributes on whichever object you deem to be the owner of those keys (e.g, current_user, current_user.account, User.new) which makes it one-to-many and quite flexible.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            === Schema
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            You are going to want a model with a schema that at least looks like this, you can call it what you wish:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              create_table :access_keys, :force => true do |t|
         | 
| 18 | 
            +
                t.string   "token_a", "token_b", :limit => 999
         | 
| 19 | 
            +
                t.string   "service", "type", :null => false
         | 
| 20 | 
            +
                t.string   "owner_type"
         | 
| 21 | 
            +
                t.integer  "owner_id"
         | 
| 22 | 
            +
                t.datetime "created_at", "updated_at", :null => false
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            === Model
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            Go ahead and add your provider details to the model, like so:
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              class AccessKey < ActiveRecord::Base
         | 
| 30 | 
            +
                oauth do
         | 
| 31 | 
            +
                  provider '37signals' do
         | 
| 32 | 
            +
                    key    'YOUR_KEY_HERE'
         | 
| 33 | 
            +
                    secret 'YOUR_SECRET_HERE'
         | 
| 34 | 
            +
                    site   'https://launchpad.37signals.com'
         | 
| 35 | 
            +
                    authorize_path     '/authorization/new'
         | 
| 36 | 
            +
                    access_token_path  '/authorization/token'
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                  provider 'LinkedIn' do
         | 
| 39 | 
            +
                    key    'YOUR_KEY_HERE'
         | 
| 40 | 
            +
                    secret 'YOUR_SECRET_HERE'
         | 
| 41 | 
            +
                    site   'https://api.linkedin.com'
         | 
| 42 | 
            +
                    authorize_path     '/uas/oauth/authorize'
         | 
| 43 | 
            +
                    access_token_path  '/uas/oauth/accessToken'
         | 
| 44 | 
            +
                    request_token_path '/uas/oauth/requestToken'
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            === Controller
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            You are going to want a controller that is able to handle the requests:
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              class OauthController < ApplicationController
         | 
| 54 | 
            +
                ssl_required :create
         | 
| 55 | 
            +
                processes_oauth_transactions_for :access_keys, 
         | 
| 56 | 
            +
                                                 :through  => lambda { current_user }, 
         | 
| 57 | 
            +
                                                 :callback => lambda { oauth_callback_url }
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
              
         | 
| 60 | 
            +
              class AccessKeysController < ApplicationController
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                def index
         | 
| 63 | 
            +
                  @access_keys = current_user.access_keys
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def show
         | 
| 67 | 
            +
                  @access_key = current_user.access_keys.find(params[:id])
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                def delete
         | 
| 71 | 
            +
                  access_key = current_user.access_keys.find(params[:id])
         | 
| 72 | 
            +
                  access_key.destroy
         | 
| 73 | 
            +
                  redirect_to access_keys_path
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
                
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            === Routes
         | 
| 79 | 
            +
             | 
| 80 | 
            +
            And maybe some routes:
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              map.resources :access_keys, :only => [:index, :show, :delete]
         | 
| 83 | 
            +
              
         | 
| 84 | 
            +
              map.oauth_authorize '/:service/oauth/start',    :controller => 'oauth', :action => 'new'
         | 
| 85 | 
            +
              map.oauth_callback  '/:service/oauth/callback', :controller => 'oauth', :action => 'create', :protocol => 'https'
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            === Usage
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            Now OAuth is as simple as adding a link:
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              <%= link_to 'Integrate your account with your 37signals account', oauth_authorize_path(:service => '37signals') %>
         | 
| 4 92 |  | 
| 5 93 | 
             
            == Note on Patches/Pull Requests
         | 
| 6 94 |  | 
    
        data/Rakefile
    CHANGED
    
    | @@ -6,11 +6,13 @@ begin | |
| 6 6 | 
             
              Jeweler::Tasks.new do |gem|
         | 
| 7 7 | 
             
                gem.name = "lasso"
         | 
| 8 8 | 
             
                gem.summary = %Q{Identity herding with OAuth}
         | 
| 9 | 
            -
                gem.description = %Q{ | 
| 9 | 
            +
                gem.description = %Q{Identity herding with OAuth}
         | 
| 10 10 | 
             
                gem.email = "james@marginleft.com"
         | 
| 11 11 | 
             
                gem.homepage = "http://github.com/jamesdaniels/lasso"
         | 
| 12 12 | 
             
                gem.authors = ["James Daniels"]
         | 
| 13 13 | 
             
                gem.add_development_dependency "rspec", ">= 1.2.9"
         | 
| 14 | 
            +
                gem.add_dependency "oauth2", ">= 0.0.10"
         | 
| 15 | 
            +
                gem.add_dependency "oauth"
         | 
| 14 16 | 
             
                # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
         | 
| 15 17 | 
             
              end
         | 
| 16 18 | 
             
              Jeweler::GemcutterTasks.new
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.1.0
         | 
    
        data/lasso.gemspec
    CHANGED
    
    | @@ -5,12 +5,12 @@ | |
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{lasso}
         | 
| 8 | 
            -
              s.version = "0. | 
| 8 | 
            +
              s.version = "0.1.0"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["James Daniels"]
         | 
| 12 | 
            -
              s.date = %q{2010-06- | 
| 13 | 
            -
              s.description = %q{ | 
| 12 | 
            +
              s.date = %q{2010-06-26}
         | 
| 13 | 
            +
              s.description = %q{Identity herding with OAuth}
         | 
| 14 14 | 
             
              s.email = %q{james@marginleft.com}
         | 
| 15 15 | 
             
              s.extra_rdoc_files = [
         | 
| 16 16 | 
             
                "LICENSE",
         | 
| @@ -25,6 +25,19 @@ Gem::Specification.new do |s| | |
| 25 25 | 
             
                 "VERSION",
         | 
| 26 26 | 
             
                 "lasso.gemspec",
         | 
| 27 27 | 
             
                 "lib/lasso.rb",
         | 
| 28 | 
            +
                 "lib/lasso/controller/base.rb",
         | 
| 29 | 
            +
                 "lib/lasso/controller/instance.rb",
         | 
| 30 | 
            +
                 "lib/lasso/controller/settings.rb",
         | 
| 31 | 
            +
                 "lib/lasso/model/base.rb",
         | 
| 32 | 
            +
                 "lib/lasso/model/instance.rb",
         | 
| 33 | 
            +
                 "lib/lasso/model/oauth_one.rb",
         | 
| 34 | 
            +
                 "lib/lasso/model/oauth_two.rb",
         | 
| 35 | 
            +
                 "lib/lasso/model/settings.rb",
         | 
| 36 | 
            +
                 "spec/controllers.rb",
         | 
| 37 | 
            +
                 "spec/db/database.yml",
         | 
| 38 | 
            +
                 "spec/db/models.rb",
         | 
| 39 | 
            +
                 "spec/db/schema.rb",
         | 
| 40 | 
            +
                 "spec/db/test.sqlite3",
         | 
| 28 41 | 
             
                 "spec/lasso_spec.rb",
         | 
| 29 42 | 
             
                 "spec/spec.opts",
         | 
| 30 43 | 
             
                 "spec/spec_helper.rb"
         | 
| @@ -35,7 +48,10 @@ Gem::Specification.new do |s| | |
| 35 48 | 
             
              s.rubygems_version = %q{1.3.6}
         | 
| 36 49 | 
             
              s.summary = %q{Identity herding with OAuth}
         | 
| 37 50 | 
             
              s.test_files = [
         | 
| 38 | 
            -
                "spec/ | 
| 51 | 
            +
                "spec/controllers.rb",
         | 
| 52 | 
            +
                 "spec/db/models.rb",
         | 
| 53 | 
            +
                 "spec/db/schema.rb",
         | 
| 54 | 
            +
                 "spec/lasso_spec.rb",
         | 
| 39 55 | 
             
                 "spec/spec_helper.rb"
         | 
| 40 56 | 
             
              ]
         | 
| 41 57 |  | 
| @@ -45,11 +61,17 @@ Gem::Specification.new do |s| | |
| 45 61 |  | 
| 46 62 | 
             
                if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
         | 
| 47 63 | 
             
                  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
         | 
| 64 | 
            +
                  s.add_runtime_dependency(%q<oauth2>, [">= 0.0.10"])
         | 
| 65 | 
            +
                  s.add_runtime_dependency(%q<oauth>, [">= 0"])
         | 
| 48 66 | 
             
                else
         | 
| 49 67 | 
             
                  s.add_dependency(%q<rspec>, [">= 1.2.9"])
         | 
| 68 | 
            +
                  s.add_dependency(%q<oauth2>, [">= 0.0.10"])
         | 
| 69 | 
            +
                  s.add_dependency(%q<oauth>, [">= 0"])
         | 
| 50 70 | 
             
                end
         | 
| 51 71 | 
             
              else
         | 
| 52 72 | 
             
                s.add_dependency(%q<rspec>, [">= 1.2.9"])
         | 
| 73 | 
            +
                s.add_dependency(%q<oauth2>, [">= 0.0.10"])
         | 
| 74 | 
            +
                s.add_dependency(%q<oauth>, [">= 0"])
         | 
| 53 75 | 
             
              end
         | 
| 54 76 | 
             
            end
         | 
| 55 77 |  | 
    
        data/lib/lasso.rb
    CHANGED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'active_record'
         | 
| 3 | 
            +
            require 'action_controller'
         | 
| 4 | 
            +
            require 'oauth2'
         | 
| 5 | 
            +
            require 'oauth'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Lasso
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              autoload :Controller, 'lasso/controller/base'
         | 
| 10 | 
            +
              autoload :Model,      'lasso/model/base'
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              def processes_oauth_transactions_for(model, settings = {})
         | 
| 13 | 
            +
                include Lasso::Controller
         | 
| 14 | 
            +
                self.oauth_model = model
         | 
| 15 | 
            +
                self.oauth_settings = settings
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
              def oauth
         | 
| 19 | 
            +
                include Lasso::Model
         | 
| 20 | 
            +
                yield if block_given?
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ActiveRecord::Base.extend Lasso
         | 
| 26 | 
            +
            ActionController::Base.extend Lasso
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            module Lasso
         | 
| 2 | 
            +
              module Controller  
         | 
| 3 | 
            +
                autoload :Settings,        'lasso/controller/settings'
         | 
| 4 | 
            +
                autoload :InstanceMethods, 'lasso/controller/instance'
         | 
| 5 | 
            +
                def self.included(base)
         | 
| 6 | 
            +
                  base.class_eval do
         | 
| 7 | 
            +
                    extend Lasso::Controller::Settings
         | 
| 8 | 
            +
                    include InstanceMethods
         | 
| 9 | 
            +
                    cattr_accessor :oauth_model
         | 
| 10 | 
            +
                    cattr_accessor :oauth_settings
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            module Lasso
         | 
| 2 | 
            +
              module Controller
         | 
| 3 | 
            +
                module InstanceMethods
         | 
| 4 | 
            +
                  def new
         | 
| 5 | 
            +
                    @oauth = type.new(:service => params[:service])
         | 
| 6 | 
            +
                    redirect
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def create
         | 
| 10 | 
            +
                    @oauth = type.new(:service => params[:service])
         | 
| 11 | 
            +
                    #@oauth = oauth_settings[:through].call.send(oauth_model).new(:service => params[:service])
         | 
| 12 | 
            +
                    parse_response
         | 
| 13 | 
            +
                    @owner = oauth_settings[:through].bind(self).call
         | 
| 14 | 
            +
                    nested = {"#{oauth_model}_attributes" => [@oauth.attributes]}
         | 
| 15 | 
            +
                    if @owner.update_attributes(nested)
         | 
| 16 | 
            +
                      redirect_to send("#{oauth_model.to_s.singularize}_path", @owner.send(oauth_model).last)
         | 
| 17 | 
            +
                    else
         | 
| 18 | 
            +
                      render :text => @oauth.to_yaml
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                protected
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def type
         | 
| 25 | 
            +
                    "OAuth#{version_one? && 'One' || 'Two'}#{oauth_model_constant}".constantize
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                  
         | 
| 28 | 
            +
                  def oauth_model_constant
         | 
| 29 | 
            +
                    oauth_model.to_s.singularize.camelcase.constantize
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def version_one?
         | 
| 33 | 
            +
                    @version_one ||= oauth_model_constant.oauth_providers[params[:service]][:oauth_version] == 1
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def parse_response
         | 
| 37 | 
            +
                    if version_one?
         | 
| 38 | 
            +
                      request_token = session[:request_token]
         | 
| 39 | 
            +
                      access_token = request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])
         | 
| 40 | 
            +
                      @oauth.attributes = {:oauth_token => access_token.params[:oauth_token], :oauth_token_secret => access_token.params[:oauth_token_secret]}
         | 
| 41 | 
            +
                    else
         | 
| 42 | 
            +
                      access_token = @oauth.client.web_server.get_access_token(params[:code], :redirect_uri => oauth_settings[:callback].bind(self).call)
         | 
| 43 | 
            +
                      @oauth.attributes = {:refresh_token => access_token.refresh_token, :access_token => access_token.token}
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  def redirect
         | 
| 48 | 
            +
                    if version_one?
         | 
| 49 | 
            +
                      @request_token = @oauth.consumer.get_request_token(:oauth_callback => oauth_settings[:callback].bind(self).call)
         | 
| 50 | 
            +
                      session[:request_token] = @request_token
         | 
| 51 | 
            +
                      redirect_to @request_token.authorize_url
         | 
| 52 | 
            +
                    else
         | 
| 53 | 
            +
                      redirect_to @oauth.client.web_server.authorize_url(:redirect_uri => oauth_settings[:callback].bind(self).call)
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            require 'lasso/model/oauth_one'
         | 
| 2 | 
            +
            require 'lasso/model/oauth_two'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Lasso
         | 
| 5 | 
            +
              module Model  
         | 
| 6 | 
            +
                autoload :Settings,        'lasso/model/settings'
         | 
| 7 | 
            +
                autoload :InstanceMethods, 'lasso/model/instance'
         | 
| 8 | 
            +
                def self.included(base)
         | 
| 9 | 
            +
                  unless ("OAuthOne".constantize rescue false)
         | 
| 10 | 
            +
                    base.class_eval do
         | 
| 11 | 
            +
                      extend Lasso::Model::Settings
         | 
| 12 | 
            +
                      include InstanceMethods
         | 
| 13 | 
            +
                      validates_presence_of :service
         | 
| 14 | 
            +
                      belongs_to :owner, :polymorphic => true
         | 
| 15 | 
            +
                      before_create :set_type
         | 
| 16 | 
            +
                      cattr_accessor :oauth_providers
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                    define_oauth_one(base)
         | 
| 19 | 
            +
                    define_oauth_two(base)
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            def define_oauth_one(parent)
         | 
| 2 | 
            +
              eval <<OAUTHONE
         | 
| 3 | 
            +
                class OAuthOne#{parent} < #{parent}
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  alias_attribute :oauth_token,        :token_a
         | 
| 6 | 
            +
                  alias_attribute :oauth_token_secret, :token_b
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  validates_presence_of :oauth_token, :oauth_token_secret
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  def consumer
         | 
| 11 | 
            +
                    @consumer ||= OAuth::Consumer.new(config(:key), config(:secret), :site => config(:site), :request_token_path => config(:request_token_path), :authorize_path => config(:authorize_path), :access_token_path => config(:access_token_path))
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def client
         | 
| 15 | 
            +
                    @client ||= case service
         | 
| 16 | 
            +
                      when 'linkedin'
         | 
| 17 | 
            +
                        LinkedIn::Client.new(config(:key), config(:secret))
         | 
| 18 | 
            +
                      when 'twitter'
         | 
| 19 | 
            +
                        Twitter::OAuth.new(config(:key), config(:secret))
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def access
         | 
| 24 | 
            +
                    unless @access
         | 
| 25 | 
            +
                      client.authorize_from_access(oauth_token, oauth_token_secret)
         | 
| 26 | 
            +
                      @access ||= case service
         | 
| 27 | 
            +
                        when 'linkedin'
         | 
| 28 | 
            +
                          client
         | 
| 29 | 
            +
                        when 'twitter'
         | 
| 30 | 
            +
                          Twitter::Base.new(client)
         | 
| 31 | 
            +
                      end
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                    @access
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
            OAUTHONE
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            def define_oauth_two(parent)
         | 
| 2 | 
            +
              eval <<OAUTHTWO
         | 
| 3 | 
            +
                class OAuthTwo#{parent} < #{parent}
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                  alias_attribute :access_token,  :token_a
         | 
| 6 | 
            +
                  alias_attribute :refresh_token, :token_b
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
                  validates_presence_of :access_token
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
                  def client
         | 
| 11 | 
            +
                    @client ||= OAuth2::Client.new(config(:key), config(:secret), :site => config(:site), :authorize_path => config(:authorize_path), :type => 'web_server', :access_token_path => config(:access_token_path))
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
                  def access
         | 
| 15 | 
            +
                    @access ||= OAuth2::AccessToken.new(client, access_token, refresh_token)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
            OAUTHTWO
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module Lasso
         | 
| 2 | 
            +
              module Model 
         | 
| 3 | 
            +
                module Settings
         | 
| 4 | 
            +
                  class Provider
         | 
| 5 | 
            +
                    def method_missing(symbol, *args)
         | 
| 6 | 
            +
                      @settings ||= {}
         | 
| 7 | 
            +
                      @settings[symbol] = args.first
         | 
| 8 | 
            +
                    end
         | 
| 9 | 
            +
                    def to_h
         | 
| 10 | 
            +
                      @settings || {}
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                  end 
         | 
| 13 | 
            +
                  RequiredSettings = [:site, :key, :secret, :site, :authorize_path, :access_token_path]
         | 
| 14 | 
            +
                  def provider(name, &block)
         | 
| 15 | 
            +
                    raise ArgumentError, 'Need to define the name' if name.blank?
         | 
| 16 | 
            +
                    p = Lasso::Model::Settings::Provider.new
         | 
| 17 | 
            +
                    block.bind(p).call
         | 
| 18 | 
            +
                    settings = p.to_h
         | 
| 19 | 
            +
                    settings[:oauth_version] = settings[:request_token_path].blank? && 2 || 1
         | 
| 20 | 
            +
                    missing_settings = RequiredSettings.map{|s| settings[s].blank? && s || nil}.compact
         | 
| 21 | 
            +
                    raise ArgumentError, "Need to define #{missing_settings.join(', ')} for any provider" unless missing_settings.empty? 
         | 
| 22 | 
            +
                    raise ArgumentError, "Need to define request_token_path for OAuth 1 providers" if settings[:oauth_version] == 1 && settings[:request_token_path].blank?
         | 
| 23 | 
            +
                    self.oauth_providers ||= {}
         | 
| 24 | 
            +
                    self.oauth_providers[name] = settings
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
    
        data/spec/controllers.rb
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            class ApplicationController < ActionController::Base
         | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              helper_method :current_user
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              def current_user
         | 
| 6 | 
            +
                @mock_user ||= mock(User, :id => 1, :login => 'someone')
         | 
| 7 | 
            +
                User.stub!('find').with(1).and_return(@mock_user)
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            class SimpleOauthsController < ApplicationController
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
              processes_oauth_transactions_for :simple_oauths, 
         | 
| 15 | 
            +
                                               :through  => lambda { current_user }, 
         | 
| 16 | 
            +
                                               :callback => lambda { "https://localhost/#{params[:service]}/callback" }
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            class OauthRegistrationController < ApplicationController
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
              processes_oauth_transactions_for :simple_oauths, 
         | 
| 23 | 
            +
                                               :through  => lambda { User.new },
         | 
| 24 | 
            +
                                               :callback => lambda { "https://localhost/#{params[:service]}/callback" }
         | 
| 25 | 
            +
              
         | 
| 26 | 
            +
            end
         | 
    
        data/spec/db/models.rb
    ADDED
    
    | @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            class SimpleOauth < ActiveRecord::Base
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              oauth do
         | 
| 4 | 
            +
                provider 'Someone' do
         | 
| 5 | 
            +
                  key    'asdf'
         | 
| 6 | 
            +
                  secret 'asdf'
         | 
| 7 | 
            +
                  site   'https://www.google.com'
         | 
| 8 | 
            +
                  authorize_path     'asdf'
         | 
| 9 | 
            +
                  access_token_path  'asdf'
         | 
| 10 | 
            +
                  request_token_path 'asdfff'
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                provider 'GitHub' do
         | 
| 13 | 
            +
                  key    'asdf'
         | 
| 14 | 
            +
                  secret 'asdf'
         | 
| 15 | 
            +
                  site   'https://www.github.com'
         | 
| 16 | 
            +
                  authorize_path    'asdf'
         | 
| 17 | 
            +
                  access_token_path 'asdf'
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                provider 'Facebook' do
         | 
| 20 | 
            +
                  key    'asdf'
         | 
| 21 | 
            +
                  secret 'asdf'
         | 
| 22 | 
            +
                  site   'https://www.facebook.com'
         | 
| 23 | 
            +
                  authorize_path    'asdf'
         | 
| 24 | 
            +
                  access_token_path 'asdf'
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            class User < ActiveRecord::Base
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
              has_many :simple_oauths, :dependent => :destroy, :as => :owner
         | 
| 33 | 
            +
              
         | 
| 34 | 
            +
              accepts_nested_attributes_for :simple_oauths
         | 
| 35 | 
            +
              
         | 
| 36 | 
            +
              with_options :unless => :using_sso? do |without_sso|
         | 
| 37 | 
            +
                without_sso.validates_presence_of :username, :password
         | 
| 38 | 
            +
                without_sso.validates_confirmation_of :password
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
              
         | 
| 41 | 
            +
              def using_sso?
         | 
| 42 | 
            +
                !simple_oauths.empty?
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
              
         | 
| 45 | 
            +
            end
         | 
    
        data/spec/db/schema.rb
    ADDED
    
    | @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            ActiveRecord::Schema.define(:version => 1) do
         | 
| 2 | 
            +
              create_table :simple_oauths, :force => true do |t|
         | 
| 3 | 
            +
                t.string   "token_a", "token_b", :limit => 999
         | 
| 4 | 
            +
                t.string   "service", "type", :null => false
         | 
| 5 | 
            +
                t.string   "owner_type"
         | 
| 6 | 
            +
                t.integer  "owner_id"
         | 
| 7 | 
            +
                t.datetime "created_at", "updated_at", :null => false
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              create_table :users, :force => true do |t|
         | 
| 10 | 
            +
                t.string 'login', 'password'
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| Binary file | 
    
        data/spec/lasso_spec.rb
    CHANGED
    
    | @@ -1,7 +1,141 @@ | |
| 1 1 | 
             
            require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 3 | 
            +
            # Test extension
         | 
| 4 | 
            +
            [SimpleOauth, SimpleOauthsController, OauthRegistrationController, ActiveRecord::Base, ActionController::Base].each do |klass|
         | 
| 5 | 
            +
              describe klass do
         | 
| 6 | 
            +
                it 'should extend out module' do
         | 
| 7 | 
            +
                  klass.is_a?(Lasso).should be_true
         | 
| 8 | 
            +
                end   
         | 
| 9 | 
            +
                [:processes_oauth_transactions_for, :oauth].each do |method|
         | 
| 10 | 
            +
                  it "should respond to #{method}" do
         | 
| 11 | 
            +
                    klass.respond_to?(method).should be_true
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 6 14 | 
             
              end
         | 
| 7 15 | 
             
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            {SimpleOauth => :model, SimpleOauthsController => :controller, OauthRegistrationController => :controller}.each do |klass, type|
         | 
| 18 | 
            +
              describe klass do
         | 
| 19 | 
            +
                {
         | 
| 20 | 
            +
                  Lasso::Model => (type == :model), 
         | 
| 21 | 
            +
                  Lasso::Model::InstanceMethods => (type == :model),
         | 
| 22 | 
            +
                  Lasso::Controller => (type == :controller),
         | 
| 23 | 
            +
                  Lasso::Controller::InstanceMethods => (type == :controller)
         | 
| 24 | 
            +
                }.each do |included, truthiness|
         | 
| 25 | 
            +
                  it "should #{truthiness && '' || 'not '}include #{included}" do
         | 
| 26 | 
            +
                    klass.include?(included).should eql(truthiness)
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
                {
         | 
| 30 | 
            +
                  Lasso::Model::Settings => (type == :model),
         | 
| 31 | 
            +
                  Lasso::Controller::Settings => (type == :controller)
         | 
| 32 | 
            +
                }.each do |extended, truthiness|
         | 
| 33 | 
            +
                  it "should #{truthiness && '' || 'not '}extend #{extended}" do
         | 
| 34 | 
            +
                    klass.is_a?(extended).should eql(truthiness)
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            describe SimpleOauth do
         | 
| 41 | 
            +
              describe 'Settings' do 
         | 
| 42 | 
            +
                describe 'Existing' do
         | 
| 43 | 
            +
                  it 'should have a GitHub provider' do
         | 
| 44 | 
            +
                    SimpleOauth.oauth_providers['GitHub'].blank?.should be_false
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  it 'should have a Facebook provider' do
         | 
| 47 | 
            +
                    SimpleOauth.oauth_providers['Facebook'].blank?.should be_false
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                  it 'should have a Someone provider' do
         | 
| 50 | 
            +
                    SimpleOauth.oauth_providers['Someone'].blank?.should be_false
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                  it 'should have the right GitHub settings' do 
         | 
| 53 | 
            +
                    SimpleOauth.oauth_providers['GitHub'].should eql({:key => 'asdf', :secret => 'asdf', :site => 'https://www.github.com', :authorize_path => 'asdf', :access_token_path => 'asdf', :oauth_version => 2})
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                  it 'should have the right Facebook settings' do
         | 
| 56 | 
            +
                    SimpleOauth.oauth_providers['Facebook'].should eql({:key => 'asdf', :secret => 'asdf', :site => 'https://www.facebook.com', :authorize_path => 'asdf', :access_token_path => 'asdf', :oauth_version => 2})
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                  it 'should have the right Someone settings' do
         | 
| 59 | 
            +
                    SimpleOauth.oauth_providers['Someone'].should eql({:key => 'asdf', :secret => 'asdf', :site => 'https://www.google.com', :authorize_path => 'asdf', :access_token_path => 'asdf', :oauth_version => 1,  :request_token_path=>"asdfff"})
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
                describe 'New' do
         | 
| 63 | 
            +
                  Settings = {:key => 'asdf', :secret => 'asdf', :site => 'https://www.google.com', :authorize_path => 'asdf', :access_token_path => 'asdf', :oauth_version => 1,  :request_token_path=>"asdfff"}
         | 
| 64 | 
            +
                  it 'should be able to add a new provider' do
         | 
| 65 | 
            +
                    SimpleOauth.class_eval do 
         | 
| 66 | 
            +
                      oauth do
         | 
| 67 | 
            +
                        provider 'ASDF' do 
         | 
| 68 | 
            +
                          key Settings[:key]
         | 
| 69 | 
            +
                          secret Settings[:secret]
         | 
| 70 | 
            +
                          site Settings[:site]
         | 
| 71 | 
            +
                          authorize_path Settings[:authorize_path]
         | 
| 72 | 
            +
                          access_token_path Settings[:access_token_path]
         | 
| 73 | 
            +
                          request_token_path Settings[:request_token_path]
         | 
| 74 | 
            +
                        end
         | 
| 75 | 
            +
                      end
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                  it 'should have the proper settings' do
         | 
| 79 | 
            +
                    SimpleOauth.oauth_providers['ASDF'].should eql(Settings)
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                  Lasso::Model::Settings::RequiredSettings.each do |required_key|
         | 
| 82 | 
            +
                    it "should require #{required_key} be set" do
         | 
| 83 | 
            +
                      lambda {
         | 
| 84 | 
            +
                        SimpleOauth.class_eval do
         | 
| 85 | 
            +
                          oauth do
         | 
| 86 | 
            +
                            provider 'ASDF' do
         | 
| 87 | 
            +
                              key Settings[:key] unless required_key == :key
         | 
| 88 | 
            +
                              secret Settings[:secret] unless required_key == :secret
         | 
| 89 | 
            +
                              site Settings[:site] unless required_key == :site
         | 
| 90 | 
            +
                              authorize_path Settings[:authorize_path] unless required_key == :authorize_path
         | 
| 91 | 
            +
                              access_token_path Settings[:access_token_path] unless required_key == :access_token_path
         | 
| 92 | 
            +
                              request_token_path Settings[:request_token_path] unless required_key == :request_token_path
         | 
| 93 | 
            +
                            end
         | 
| 94 | 
            +
                          end
         | 
| 95 | 
            +
                        end
         | 
| 96 | 
            +
                      }.should raise_error(ArgumentError)
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
                    it "should require #{required_key} to have a non-empty value" do
         | 
| 99 | 
            +
                      lambda {
         | 
| 100 | 
            +
                        settings = Settings.merge(required_key => '')
         | 
| 101 | 
            +
                        SimpleOauth.class_eval do
         | 
| 102 | 
            +
                          oauth do
         | 
| 103 | 
            +
                            provider 'ASDF' do
         | 
| 104 | 
            +
                              key settings[:key]
         | 
| 105 | 
            +
                              secret settings[:secret]
         | 
| 106 | 
            +
                              site settings[:site]
         | 
| 107 | 
            +
                              authorize_path settings[:authorize_path]
         | 
| 108 | 
            +
                              access_token_path settings[:access_token_path]
         | 
| 109 | 
            +
                              request_token_path settings[:request_token_path]
         | 
| 110 | 
            +
                            end
         | 
| 111 | 
            +
                          end
         | 
| 112 | 
            +
                        end
         | 
| 113 | 
            +
                      }.should raise_error(ArgumentError)
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
              end
         | 
| 118 | 
            +
            end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            describe User do
         | 
| 121 | 
            +
              it 'should require password/username without sso' do
         | 
| 122 | 
            +
                User.new.should_not be_valid
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
              it 'should work with nested attributes' do
         | 
| 125 | 
            +
                (user = User.new(:simple_oauths_attributes => [{ :token_a => 'asdf', :token_b => 'adsf', :service => 'GitHub' }])).should be_valid
         | 
| 126 | 
            +
                user.save!
         | 
| 127 | 
            +
                user.reload
         | 
| 128 | 
            +
                user.simple_oauths.empty?.should be_false
         | 
| 129 | 
            +
                user.simple_oauths.first.class.should eql(OAuthTwoSimpleOauth)
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
            end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
            describe SimpleOauthsController do
         | 
| 134 | 
            +
              describe 'Settings' do 
         | 
| 135 | 
            +
                describe 'Existing' do
         | 
| 136 | 
            +
                  it 'should have an oauth_model' do
         | 
| 137 | 
            +
                    SimpleOauthsController.oauth_model.should eql(:simple_oauths)
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
              end
         | 
| 141 | 
            +
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -1,9 +1,27 @@ | |
| 1 1 | 
             
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         | 
| 2 2 | 
             
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         | 
| 3 3 | 
             
            require 'lasso'
         | 
| 4 | 
            +
            require 'active_record'
         | 
| 5 | 
            +
            require 'active_record/fixtures'
         | 
| 6 | 
            +
            require 'action_controller'
         | 
| 7 | 
            +
            require 'active_support'
         | 
| 4 8 | 
             
            require 'spec'
         | 
| 5 9 | 
             
            require 'spec/autorun'
         | 
| 6 10 |  | 
| 11 | 
            +
            # establish the database connection
         | 
| 12 | 
            +
            ActiveRecord::Base.configurations = YAML::load(IO.read(File.dirname(__FILE__) + '/db/database.yml'))
         | 
| 13 | 
            +
            ActiveRecord::Base.establish_connection('active_record_merge_test')
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            # load the schema
         | 
| 16 | 
            +
            $stdout = File.open('/dev/null', 'w')
         | 
| 17 | 
            +
            load(File.dirname(__FILE__) + "/db/schema.rb")
         | 
| 18 | 
            +
            $stdout = STDOUT
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            # load the models
         | 
| 21 | 
            +
            require File.dirname(__FILE__) + '/db/models'
         | 
| 22 | 
            +
            require File.dirname(__FILE__) + '/controllers'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
             | 
| 7 25 | 
             
            Spec::Runner.configure do |config|
         | 
| 8 26 |  | 
| 9 27 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version | |
| 4 4 | 
             
              prerelease: false
         | 
| 5 5 | 
             
              segments: 
         | 
| 6 6 | 
             
              - 0
         | 
| 7 | 
            +
              - 1
         | 
| 7 8 | 
             
              - 0
         | 
| 8 | 
            -
               | 
| 9 | 
            -
              version: 0.0.0
         | 
| 9 | 
            +
              version: 0.1.0
         | 
| 10 10 | 
             
            platform: ruby
         | 
| 11 11 | 
             
            authors: 
         | 
| 12 12 | 
             
            - James Daniels
         | 
| @@ -14,7 +14,7 @@ autorequire: | |
| 14 14 | 
             
            bindir: bin
         | 
| 15 15 | 
             
            cert_chain: []
         | 
| 16 16 |  | 
| 17 | 
            -
            date: 2010-06- | 
| 17 | 
            +
            date: 2010-06-26 00:00:00 -04:00
         | 
| 18 18 | 
             
            default_executable: 
         | 
| 19 19 | 
             
            dependencies: 
         | 
| 20 20 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -31,7 +31,33 @@ dependencies: | |
| 31 31 | 
             
                    version: 1.2.9
         | 
| 32 32 | 
             
              type: :development
         | 
| 33 33 | 
             
              version_requirements: *id001
         | 
| 34 | 
            -
             | 
| 34 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 35 | 
            +
              name: oauth2
         | 
| 36 | 
            +
              prerelease: false
         | 
| 37 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 38 | 
            +
                requirements: 
         | 
| 39 | 
            +
                - - ">="
         | 
| 40 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 41 | 
            +
                    segments: 
         | 
| 42 | 
            +
                    - 0
         | 
| 43 | 
            +
                    - 0
         | 
| 44 | 
            +
                    - 10
         | 
| 45 | 
            +
                    version: 0.0.10
         | 
| 46 | 
            +
              type: :runtime
         | 
| 47 | 
            +
              version_requirements: *id002
         | 
| 48 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 49 | 
            +
              name: oauth
         | 
| 50 | 
            +
              prerelease: false
         | 
| 51 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 52 | 
            +
                requirements: 
         | 
| 53 | 
            +
                - - ">="
         | 
| 54 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 55 | 
            +
                    segments: 
         | 
| 56 | 
            +
                    - 0
         | 
| 57 | 
            +
                    version: "0"
         | 
| 58 | 
            +
              type: :runtime
         | 
| 59 | 
            +
              version_requirements: *id003
         | 
| 60 | 
            +
            description: Identity herding with OAuth
         | 
| 35 61 | 
             
            email: james@marginleft.com
         | 
| 36 62 | 
             
            executables: []
         | 
| 37 63 |  | 
| @@ -49,6 +75,19 @@ files: | |
| 49 75 | 
             
            - VERSION
         | 
| 50 76 | 
             
            - lasso.gemspec
         | 
| 51 77 | 
             
            - lib/lasso.rb
         | 
| 78 | 
            +
            - lib/lasso/controller/base.rb
         | 
| 79 | 
            +
            - lib/lasso/controller/instance.rb
         | 
| 80 | 
            +
            - lib/lasso/controller/settings.rb
         | 
| 81 | 
            +
            - lib/lasso/model/base.rb
         | 
| 82 | 
            +
            - lib/lasso/model/instance.rb
         | 
| 83 | 
            +
            - lib/lasso/model/oauth_one.rb
         | 
| 84 | 
            +
            - lib/lasso/model/oauth_two.rb
         | 
| 85 | 
            +
            - lib/lasso/model/settings.rb
         | 
| 86 | 
            +
            - spec/controllers.rb
         | 
| 87 | 
            +
            - spec/db/database.yml
         | 
| 88 | 
            +
            - spec/db/models.rb
         | 
| 89 | 
            +
            - spec/db/schema.rb
         | 
| 90 | 
            +
            - spec/db/test.sqlite3
         | 
| 52 91 | 
             
            - spec/lasso_spec.rb
         | 
| 53 92 | 
             
            - spec/spec.opts
         | 
| 54 93 | 
             
            - spec/spec_helper.rb
         | 
| @@ -83,5 +122,8 @@ signing_key: | |
| 83 122 | 
             
            specification_version: 3
         | 
| 84 123 | 
             
            summary: Identity herding with OAuth
         | 
| 85 124 | 
             
            test_files: 
         | 
| 125 | 
            +
            - spec/controllers.rb
         | 
| 126 | 
            +
            - spec/db/models.rb
         | 
| 127 | 
            +
            - spec/db/schema.rb
         | 
| 86 128 | 
             
            - spec/lasso_spec.rb
         | 
| 87 129 | 
             
            - spec/spec_helper.rb
         |