omniauth-identity 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ /coverage
2
+ /pkg
3
+ /doc
4
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format=nested
2
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'guard'
7
+ gem 'guard-rspec'
8
+ gem 'guard-bundler'
9
+ gem 'growl'
10
+ gem 'rb-fsevent'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ omniauth-identity (1.0.0.beta1)
5
+ omniauth (= 1.0.0.beta1)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ activemodel (3.0.10)
11
+ activesupport (= 3.0.10)
12
+ builder (~> 2.1.2)
13
+ i18n (~> 0.5.0)
14
+ activerecord (3.0.10)
15
+ activemodel (= 3.0.10)
16
+ activesupport (= 3.0.10)
17
+ arel (~> 2.0.10)
18
+ tzinfo (~> 0.3.23)
19
+ activesupport (3.0.10)
20
+ arel (2.0.10)
21
+ bcrypt-ruby (2.1.4)
22
+ builder (2.1.2)
23
+ diff-lcs (1.1.3)
24
+ growl (1.0.3)
25
+ guard (0.8.4)
26
+ thor (~> 0.14.6)
27
+ guard-bundler (0.1.3)
28
+ bundler (>= 1.0.0)
29
+ guard (>= 0.2.2)
30
+ guard-rspec (0.4.5)
31
+ guard (>= 0.4.0)
32
+ hashie (1.2.0)
33
+ i18n (0.5.0)
34
+ maruku (0.6.0)
35
+ syntax (>= 1.0.0)
36
+ multi_json (1.0.3)
37
+ omniauth (1.0.0.beta1)
38
+ hashie (~> 1.2)
39
+ rack
40
+ rack (1.3.5)
41
+ rack-test (0.6.1)
42
+ rack (>= 1.0)
43
+ rake (0.9.2)
44
+ rb-fsevent (0.4.3.1)
45
+ rspec (2.6.0)
46
+ rspec-core (~> 2.6.0)
47
+ rspec-expectations (~> 2.6.0)
48
+ rspec-mocks (~> 2.6.0)
49
+ rspec-core (2.6.4)
50
+ rspec-expectations (2.6.0)
51
+ diff-lcs (~> 1.1.2)
52
+ rspec-mocks (2.6.0)
53
+ simplecov (0.5.3)
54
+ multi_json (~> 1.0.3)
55
+ simplecov-html (~> 0.5.3)
56
+ simplecov-html (0.5.3)
57
+ syntax (1.0.0)
58
+ thor (0.14.6)
59
+ tzinfo (0.3.30)
60
+
61
+ PLATFORMS
62
+ ruby
63
+
64
+ DEPENDENCIES
65
+ activerecord (~> 3.0)
66
+ bcrypt-ruby (~> 2.1.4)
67
+ growl
68
+ guard
69
+ guard-bundler
70
+ guard-rspec
71
+ maruku (~> 0.6)
72
+ omniauth-identity!
73
+ rack-test (~> 0.5)
74
+ rake (~> 0.8)
75
+ rb-fsevent
76
+ rspec (~> 2.5)
77
+ simplecov (~> 0.4)
data/Guardfile ADDED
@@ -0,0 +1,10 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
7
+ guard 'bundler' do
8
+ watch('Gemfile')
9
+ watch(/^.+\.gemspec/)
10
+ end
data/README.markdown ADDED
@@ -0,0 +1,90 @@
1
+ # OmniAuth Identity
2
+
3
+ The OmniAuth Identity gem provides a way for applications to utilize a
4
+ traditional login/password based authentication system without the need
5
+ to give up the simple authentication flow provided by OmniAuth. Identity
6
+ is designed on purpose to be as featureless as possible: it provides the
7
+ basic construct for user management and then gets out of the way.
8
+
9
+ ## Usage
10
+
11
+ You use `oa-identity` just like you would any other OmniAuth provider: as a
12
+ Rack middleware. The basic setup for a email/password authentication would
13
+ look something like this:
14
+
15
+ use OmniAuth::Builder do
16
+ provider :identity, :fields => [:email]
17
+ end
18
+
19
+ Next, you need to create a model (called `Identity by default`) that will be
20
+ able to persist the information provided by the user. Luckily for you, there
21
+ are pre-built models for popular ORMs that make this dead simple. You just
22
+ need to subclass the relevant class:
23
+
24
+ class Identity < OmniAuth::Identity::Models::ActiveRecord
25
+ # Add whatever you like!
26
+ end
27
+
28
+ Adapters are provided for `ActiveRecord` and `MongoMapper` and are
29
+ autoloaded on request (but not loaded by default so no dependencies are
30
+ injected).
31
+
32
+ Once you've got an Identity persistence model and the strategy up and
33
+ running, you can point users to `/auth/identity` and it will request
34
+ that they log in or give them the opportunity to sign up for an account.
35
+ Once they have authenticated with their identity, OmniAuth will call
36
+ through to `/auth/identity/callback` with the same kinds of information
37
+ it would had the user authenticated through an external provider.
38
+ Simple!
39
+
40
+ ## Custom Auth Model
41
+
42
+ To use a class other than the default, specify the <tt>:model</tt> option to a
43
+ different class.
44
+
45
+ use OmniAuth::Builder do
46
+ provider :identity, :fields => [:email], :model => MyCustomClass
47
+ end
48
+
49
+ ## Customizing Registration Failure
50
+
51
+ To use your own custom registration form, create a form that POSTs to
52
+ '/auth/identity/register' with 'password', 'password_confirmation', and your
53
+ other fields.
54
+
55
+ <%= form_tag '/auth/identity/register' do |f| %>
56
+ <h1>Create an Account</h1>
57
+ <%= text_field_tag :email %>
58
+ <%= password_field_tag, :password %>
59
+ <%= password_field_tag, :password_confirmation %>
60
+ <%= submit_tag %>
61
+ <% end %>
62
+
63
+ Beware not to nest your form parameters within a namespace. This strategy
64
+ looks for the form parameters at the top level of the post params. If you are
65
+ using [simple\_form](https://github.com/plataformatec/simple_form), then you
66
+ can avoid the params nesting by specifying <tt>:input_html</tt>.
67
+
68
+ <%= simple_form_for @identity, :url => '/auth/identity/register' do |f| %>
69
+ <h1>Create an Account</h1>
70
+ <%# specify :input_html to avoid params nesting %>
71
+ <%= f.input :email, :input_html => {:name => 'email'} %>
72
+ <%= f.input :password, :as => 'password', :input_html => {:name => 'password'} %>
73
+ <%= f.input :password_confirmation, :label => "Confirm Password", :as => 'password', :input_html => {:name => 'password_confirmation'} %>
74
+ <button type='submit'>Sign Up</button>
75
+ <% end %>
76
+
77
+ Next you'll need to let OmniAuth know what action to call when a registration
78
+ fails. In your OmniAuth configuration, specify any valid rack endpoint in the
79
+ <tt>:on_failed_registration</tt> option.
80
+
81
+ use OmniAuth::Builder do
82
+ provider :identity,
83
+ :fields => [:email],
84
+ :on_failed_registration => UsersController.action(:new)
85
+ end
86
+
87
+ For more information on rack endpoints, check out [this
88
+ introduction](http://library.edgecase.com/Rails/2011/01/04/rails-routing-and-rack-endpoints.html)
89
+ and
90
+ [ActionController::Metal](http://rubydoc.info/docs/rails/ActionController/Metal)
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ desc "Run specs."
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
9
+ task :test => :spec
@@ -0,0 +1,115 @@
1
+ module OmniAuth
2
+ module Identity
3
+ # This module provides an includable interface for implementing the
4
+ # necessary API for OmniAuth Identity to properly locate identities
5
+ # and provide all necessary information. All methods marked as
6
+ # abstract must be implemented in the including class for things to
7
+ # work properly.
8
+ module Model
9
+ def self.included(base)
10
+ base.extend ClassMethods
11
+ end
12
+
13
+ module ClassMethods
14
+ # Locate an identity given its unique login key.
15
+ #
16
+ # @abstract
17
+ # @param [String] key The unique login key.
18
+ # @return [Model] An instance of the identity model class.
19
+ def locate(key)
20
+ raise NotImplementedError
21
+ end
22
+
23
+ # Authenticate a user with the given key and password.
24
+ #
25
+ # @param [String] key The unique login key provided for a given identity.
26
+ # @param [String] password The presumed password for the identity.
27
+ # @return [Model] An instance of the identity model class.
28
+ def authenticate(key, password)
29
+ instance = locate(key)
30
+ return false unless instance
31
+ instance.authenticate(password)
32
+ end
33
+
34
+ # Used to set or retrieve the method that will be used to get
35
+ # and set the user-supplied authentication key.
36
+ # @return [String] The method name.
37
+ def auth_key(method = false)
38
+ @auth_key = method.to_s unless method == false
39
+ @auth_key = nil if @auth_key == ''
40
+
41
+ @auth_key || 'email'
42
+ end
43
+ end
44
+
45
+ # Returns self if the provided password is correct, false
46
+ # otherwise.
47
+ #
48
+ # @abstract
49
+ # @param [String] password The password to check.
50
+ # @return [self or false] Self if authenticated, false if not.
51
+ def authenticate(password)
52
+ raise NotImplementedError
53
+ end
54
+
55
+ SCHEMA_ATTRIBUTES = %w(name email nickname first_name last_name location description image phone)
56
+ # A hash of as much of the standard OmniAuth schema as is stored
57
+ # in this particular model. By default, this will call instance
58
+ # methods for each of the attributes it needs in turn, ignoring
59
+ # any for which `#respond_to?` is `false`.
60
+ #
61
+ # If `first_name`, `nickname`, and/or `last_name` is provided but
62
+ # `name` is not, it will be automatically calculated.
63
+ #
64
+ # @return [Hash] A string-keyed hash of user information.
65
+ def info
66
+ info = SCHEMA_ATTRIBUTES.inject({}) do |hash,attribute|
67
+ hash[attribute] = send(attribute) if respond_to?(attribute)
68
+ hash
69
+ end
70
+ info
71
+ end
72
+
73
+ # An identifying string that must be globally unique to the
74
+ # application. Defaults to stringifying the `id` method.
75
+ #
76
+ # @return [String] An identifier string unique to this identity.
77
+ def uid
78
+ if respond_to?('id')
79
+ return nil if self.id.nil?
80
+ self.id.to_s
81
+ else
82
+ raise NotImplementedError
83
+ end
84
+ end
85
+
86
+ # Used to retrieve the user-supplied authentication key (e.g. a
87
+ # username or email). Determined using the class method of the same name,
88
+ # defaults to `:email`.
89
+ #
90
+ # @return [String] An identifying string that will be entered by
91
+ # users upon sign in.
92
+ def auth_key
93
+ if respond_to?(self.class.auth_key)
94
+ send(self.class.auth_key)
95
+ else
96
+ raise NotImplementedError
97
+ end
98
+ end
99
+
100
+ # Used to set the user-supplied authentication key (e.g. a
101
+ # username or email. Determined using the `.auth_key` class
102
+ # method.
103
+ #
104
+ # @param [String] value The value to which the auth key should be
105
+ # set.
106
+ def auth_key=(value)
107
+ if respond_to?(self.class.auth_key + '=')
108
+ send(self.class.auth_key + '=', value)
109
+ else
110
+ raise NotImplementedError
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,24 @@
1
+ require 'active_record'
2
+
3
+ module OmniAuth
4
+ module Identity
5
+ module Models
6
+ class ActiveRecord < ::ActiveRecord::Base
7
+ include OmniAuth::Identity::Model
8
+ include OmniAuth::Identity::SecurePassword
9
+
10
+ self.abstract_class = true
11
+ has_secure_password
12
+
13
+ def self.auth_key=(key)
14
+ super
15
+ validates_uniqueness_of key, :case_sensitive => false
16
+ end
17
+
18
+ def self.locate(key)
19
+ where(auth_key => key).first
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ require 'bcrypt'
2
+
3
+ module OmniAuth
4
+ module Identity
5
+ # This is taken directly from Rails 3.1 code and is used if
6
+ # the version of ActiveModel that's being used does not
7
+ # include SecurePassword. The only difference is that instead of
8
+ # using ActiveSupport::Concern, it checks to see if there is already
9
+ # a has_secure_password method.
10
+ module SecurePassword
11
+ def self.included(base)
12
+ unless base.respond_to?(:has_secure_password)
13
+ base.extend ClassMethods
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ # Adds methods to set and authenticate against a BCrypt password.
19
+ # This mechanism requires you to have a password_digest attribute.
20
+ #
21
+ # Validations for presence of password, confirmation of password (using
22
+ # a "password_confirmation" attribute) are automatically added.
23
+ # You can add more validations by hand if need be.
24
+ #
25
+ # Example using Active Record (which automatically includes ActiveModel::SecurePassword):
26
+ #
27
+ # # Schema: User(name:string, password_digest:string)
28
+ # class User < ActiveRecord::Base
29
+ # has_secure_password
30
+ # end
31
+ #
32
+ # user = User.new(:name => "david", :password => "", :password_confirmation => "nomatch")
33
+ # user.save # => false, password required
34
+ # user.password = "mUc3m00RsqyRe"
35
+ # user.save # => false, confirmation doesn't match
36
+ # user.password_confirmation = "mUc3m00RsqyRe"
37
+ # user.save # => true
38
+ # user.authenticate("notright") # => false
39
+ # user.authenticate("mUc3m00RsqyRe") # => user
40
+ # User.find_by_name("david").try(:authenticate, "notright") # => nil
41
+ # User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user
42
+ def has_secure_password
43
+ attr_reader :password
44
+
45
+ validates_confirmation_of :password
46
+ validates_presence_of :password_digest
47
+
48
+ include InstanceMethodsOnActivation
49
+
50
+ if respond_to?(:attributes_protected_by_default)
51
+ def self.attributes_protected_by_default
52
+ super + ['password_digest']
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ module InstanceMethodsOnActivation
59
+ # Returns self if the password is correct, otherwise false.
60
+ def authenticate(unencrypted_password)
61
+ if BCrypt::Password.new(password_digest) == unencrypted_password
62
+ self
63
+ else
64
+ false
65
+ end
66
+ end
67
+
68
+ # Encrypts the password into the password_digest attribute.
69
+ def password=(unencrypted_password)
70
+ @password = unencrypted_password
71
+ unless unencrypted_password.blank?
72
+ self.password_digest = BCrypt::Password.create(unencrypted_password)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,17 @@
1
+ require 'omniauth'
2
+
3
+ module OmniAuth
4
+ module Strategies
5
+ autoload :Identity, 'omniauth/strategies/identity'
6
+ end
7
+
8
+ module Identity
9
+ autoload :Model, 'omniauth/identity/model'
10
+ autoload :SecurePassword, 'omniauth/identity/secure_password'
11
+ module Models
12
+ autoload :ActiveRecord, 'omniauth/identity/models/active_record'
13
+ # autoload :MongoMapper, 'omniauth/identity/models/mongo_mapper'
14
+ # autoload :Mongoid, 'omniauth/identity/models/mongoid'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,86 @@
1
+ module OmniAuth
2
+ module Strategies
3
+ # The identity strategy allows you to provide simple internal
4
+ # user authentication using the same process flow that you
5
+ # use for external OmniAuth providers.
6
+ class Identity
7
+ include OmniAuth::Strategy
8
+
9
+ option :fields, [:name, :email]
10
+ option :on_failed_registration, nil
11
+
12
+ def request_phase
13
+ OmniAuth::Form.build(
14
+ :title => (options[:title] || "Identity Verification"),
15
+ :url => callback_path
16
+ ) do |f|
17
+ f.text_field 'Login', 'auth_key'
18
+ f.password_field 'Password', 'password'
19
+ f.html "<p align='center'><a href='#{registration_path}'>Create an Identity</a></p>"
20
+ end.to_response
21
+ end
22
+
23
+ def callback_phase
24
+ return fail!(:invalid_credentials) unless identity
25
+ super
26
+ end
27
+
28
+ def other_phase
29
+ if on_registration_path?
30
+ if request.get?
31
+ registration_form
32
+ elsif request.post?
33
+ registration_phase
34
+ end
35
+ else
36
+ call_app!
37
+ end
38
+ end
39
+
40
+ def registration_form
41
+ OmniAuth::Form.build(:title => 'Register Identity') do |f|
42
+ options[:fields].each do |field|
43
+ f.text_field field.to_s.capitalize, field.to_s
44
+ end
45
+ f.password_field 'Password', 'password'
46
+ f.password_field 'Confirm Password', 'password_confirmation'
47
+ end.to_response
48
+ end
49
+
50
+ def registration_phase
51
+ attributes = (options[:fields] + [:password, :password_confirmation]).inject({}){|h,k| h[k] = request[k.to_s]; h}
52
+ @identity = model.create(attributes)
53
+ if @identity.persisted?
54
+ env['PATH_INFO'] = callback_path
55
+ callback_phase
56
+ else
57
+ if options[:on_failed_registration]
58
+ self.env['omniauth.identity'] = @identity
59
+ options[:on_failed_registration].call(self.env)
60
+ else
61
+ registration_form
62
+ end
63
+ end
64
+ end
65
+
66
+ uid{ identity.uid }
67
+ info{ identity.info }
68
+
69
+ def registration_path
70
+ options[:registration_path] || "#{path_prefix}/#{name}/register"
71
+ end
72
+
73
+ def on_registration_path?
74
+ on_path?(registration_path)
75
+ end
76
+
77
+ def identity
78
+ @identity ||= model.authenticate(request['auth_key'], request['password'])
79
+ end
80
+
81
+ def model
82
+ options[:model] || ::Identity
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module Identity
3
+ VERSION = '1.0.0.beta1'
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ require 'omniauth-identity/version'
2
+ require 'omniauth/identity'
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.dirname(__FILE__) + '/lib/omniauth-identity/version'
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.add_runtime_dependency 'omniauth', '1.0.0.beta1'
6
+
7
+ gem.add_development_dependency 'maruku', '~> 0.6'
8
+ gem.add_development_dependency 'simplecov', '~> 0.4'
9
+ gem.add_development_dependency 'rack-test', '~> 0.5'
10
+ gem.add_development_dependency 'rake', '~> 0.8'
11
+ gem.add_development_dependency 'rspec', '~> 2.5'
12
+ gem.add_development_dependency 'bcrypt-ruby', '~> 2.1.4'
13
+ gem.add_development_dependency 'activerecord', '~> 3.0'
14
+
15
+ gem.name = 'omniauth-identity'
16
+ gem.version = OmniAuth::Identity::VERSION
17
+ gem.description = %q{Internal authentication handlers for OmniAuth.}
18
+ gem.summary = gem.description
19
+ gem.email = ['michael@intridea.com']
20
+ gem.homepage = 'http://github.com/intridea/omniauth-identity'
21
+ gem.authors = ['Michael Bleigh']
22
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
23
+ gem.files = `git ls-files`.split("\n")
24
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ gem.require_paths = ['lib']
26
+ gem.required_rubygems_version = Gem::Requirement.new('>= 1.3.6') if gem.respond_to? :required_rubygems_version=
27
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ class ExampleModel
4
+ include OmniAuth::Identity::Model
5
+ end
6
+
7
+ describe OmniAuth::Identity::Model do
8
+ context 'Class Methods' do
9
+ subject{ ExampleModel }
10
+
11
+ describe '.locate' do
12
+ it('should be abstract'){ lambda{ subject.locate('abc') }.should raise_error(NotImplementedError) }
13
+ end
14
+
15
+ describe '.authenticate' do
16
+ it 'should call locate and then authenticate' do
17
+ mocked_instance = mock('ExampleModel', :authenticate => 'abbadoo')
18
+ subject.should_receive(:locate).with('example').and_return(mocked_instance)
19
+ subject.authenticate('example','pass').should == 'abbadoo'
20
+ end
21
+
22
+ it 'should recover gracefully if locate is nil' do
23
+ subject.stub!(:locate).and_return(nil)
24
+ subject.authenticate('blah','foo').should be_false
25
+ end
26
+ end
27
+ end
28
+
29
+ context 'Instance Methods' do
30
+ subject{ ExampleModel.new }
31
+
32
+ describe '#authenticate' do
33
+ it('should be abstract'){ lambda{ subject.authenticate('abc') }.should raise_error(NotImplementedError) }
34
+ end
35
+
36
+ describe '#uid' do
37
+ it 'should default to #id' do
38
+ subject.should_receive(:respond_to?).with('id').and_return(true)
39
+ subject.stub!(:id).and_return 'wakka-do'
40
+ subject.uid.should == 'wakka-do'
41
+ end
42
+
43
+ it 'should stringify it' do
44
+ subject.stub!(:id).and_return 123
45
+ subject.uid.should == '123'
46
+ end
47
+
48
+ it 'should raise NotImplementedError if #id is not defined' do
49
+ subject.should_receive(:respond_to?).with('id').and_return(false)
50
+ lambda{ subject.uid }.should raise_error(NotImplementedError)
51
+ end
52
+ end
53
+
54
+ describe '#auth_key' do
55
+ it 'should default to #email' do
56
+ subject.should_receive(:respond_to?).with('email').and_return(true)
57
+ subject.stub!(:email).and_return('bob@bob.com')
58
+ subject.auth_key.should == 'bob@bob.com'
59
+ end
60
+
61
+ it 'should use the class .auth_key' do
62
+ subject.class.auth_key 'login'
63
+ subject.stub!(:login).and_return 'bob'
64
+ subject.auth_key.should == 'bob'
65
+ subject.class.auth_key nil
66
+ end
67
+
68
+ it 'should raise a NotImplementedError if the auth_key method is not defined' do
69
+ lambda{ subject.auth_key }.should raise_error(NotImplementedError)
70
+ end
71
+ end
72
+
73
+ describe '#auth_key=' do
74
+ it 'should default to setting email' do
75
+ subject.should_receive(:respond_to?).with('email=').and_return(true)
76
+ subject.should_receive(:email=).with 'abc'
77
+
78
+ subject.auth_key = 'abc'
79
+ end
80
+
81
+ it 'should use a custom .auth_key if one is provided' do
82
+ subject.class.auth_key 'login'
83
+ subject.should_receive(:respond_to?).with('login=').and_return(true)
84
+ subject.should_receive('login=').with('abc')
85
+
86
+ subject.auth_key = 'abc'
87
+ end
88
+
89
+ it 'should raise a NotImplementedError if the autH_key method is not defined' do
90
+ lambda{ subject.auth_key = 'broken' }.should raise_error(NotImplementedError)
91
+ end
92
+ end
93
+
94
+ describe '#info' do
95
+ it 'should include attributes that are set' do
96
+ subject.stub!(:name).and_return('Bob Bobson')
97
+ subject.stub!(:nickname).and_return('bob')
98
+
99
+ subject.info.should == {
100
+ 'name' => 'Bob Bobson',
101
+ 'nickname' => 'bob'
102
+ }
103
+ end
104
+
105
+ it 'should automatically set name off of nickname' do
106
+ subject.stub!(:nickname).and_return('bob')
107
+ subject.info['name'] == 'bob'
108
+ end
109
+
110
+ it 'should not overwrite a provided name' do
111
+ subject.stub!(:name).and_return('Awesome Dude')
112
+ subject.stub!(:first_name).and_return('Frank')
113
+ subject.info['name'].should == 'Awesome Dude'
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe(OmniAuth::Identity::Models::ActiveRecord, :db => true) do
4
+ class TestIdentity < OmniAuth::Identity::Models::ActiveRecord
5
+ auth_key :ham_sandwich
6
+ end
7
+
8
+ it 'should locate using the auth key using a where query' do
9
+ TestIdentity.should_receive(:where).with('ham_sandwich' => 'open faced').and_return(['wakka'])
10
+ TestIdentity.locate('open faced').should == 'wakka'
11
+ end
12
+
13
+ it 'should not use STI rules for its table name' do
14
+ TestIdentity.table_name.should == 'test_identities'
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ class HasTheMethod
4
+ def self.has_secure_password; end
5
+ end
6
+
7
+ class DoesNotHaveTheMethod
8
+ end
9
+
10
+ describe OmniAuth::Identity::SecurePassword do
11
+ it 'should extend with the class methods if it does not have the method' do
12
+ DoesNotHaveTheMethod.should_receive(:extend).with(OmniAuth::Identity::SecurePassword::ClassMethods)
13
+ DoesNotHaveTheMethod.send(:include, OmniAuth::Identity::SecurePassword)
14
+ end
15
+
16
+ it 'should not extend if the method is already defined' do
17
+ HasTheMethod.should_not_receive(:extend)
18
+ HasTheMethod.send(:include, OmniAuth::Identity::SecurePassword)
19
+ end
20
+
21
+ it 'should respond to has_secure_password afterwards' do
22
+ [HasTheMethod,DoesNotHaveTheMethod].each do |klass|
23
+ klass.send(:include, OmniAuth::Identity::SecurePassword)
24
+ klass.should be_respond_to(:has_secure_password)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ class MockIdentity; end
4
+
5
+ describe OmniAuth::Strategies::Identity do
6
+ attr_accessor :app
7
+
8
+ let(:auth_hash){ last_response.headers['env']['omniauth.auth'] }
9
+ let(:identity_hash){ last_response.headers['env']['omniauth.identity'] }
10
+
11
+ # customize rack app for testing, if block is given, reverts to default
12
+ # rack app after testing is done
13
+ def set_app!(identity_options = {})
14
+ identity_options = {:model => MockIdentity}.merge(identity_options)
15
+ old_app = self.app
16
+ self.app = Rack::Builder.app do
17
+ use Rack::Session::Cookie
18
+ use OmniAuth::Strategies::Identity, identity_options
19
+ run lambda{|env| [404, {'env' => env}, ["HELLO!"]]}
20
+ end
21
+ if block_given?
22
+ yield
23
+ self.app = old_app
24
+ end
25
+ self.app
26
+ end
27
+
28
+ before(:all) do
29
+ set_app!
30
+ end
31
+
32
+ describe '#request_phase' do
33
+ it 'should display a form' do
34
+ get '/auth/identity'
35
+ last_response.body.should be_include("<form")
36
+ end
37
+ end
38
+
39
+ describe '#callback_phase' do
40
+ let(:user){ mock(:uid => 'user1', :info => {'name' => 'Rockefeller'})}
41
+
42
+ context 'with valid credentials' do
43
+ before do
44
+ MockIdentity.should_receive('authenticate').with('john','awesome').and_return(user)
45
+ post '/auth/identity/callback', :auth_key => 'john', :password => 'awesome'
46
+ end
47
+
48
+ it 'should populate the auth hash' do
49
+ auth_hash.should be_kind_of(Hash)
50
+ end
51
+
52
+ it 'should populate the uid' do
53
+ auth_hash['uid'].should == 'user1'
54
+ end
55
+
56
+ it 'should populate the info hash' do
57
+ auth_hash['info'].should == {'name' => 'Rockefeller'}
58
+ end
59
+ end
60
+
61
+ context 'with invalid credentials' do
62
+ before do
63
+ OmniAuth.config.on_failure = lambda{|env| [401, {}, [env['omniauth.error.type'].inspect]]}
64
+ MockIdentity.should_receive(:authenticate).with('wrong','login').and_return(false)
65
+ post '/auth/identity/callback', :auth_key => 'wrong', :password => 'login'
66
+ end
67
+
68
+ it 'should fail with :invalid_credentials' do
69
+ last_response.body.should == ':invalid_credentials'
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '#registration_form' do
75
+ it 'should trigger from /auth/identity/register by default' do
76
+ get '/auth/identity/register'
77
+ last_response.body.should be_include("Register Identity")
78
+ end
79
+ end
80
+
81
+ describe '#registration_phase' do
82
+ context 'with successful creation' do
83
+ let(:properties){ {
84
+ :name => 'Awesome Dude',
85
+ :email => 'awesome@example.com',
86
+ :password => 'face',
87
+ :password_confirmation => 'face'
88
+ } }
89
+
90
+ before do
91
+ m = mock(:uid => 'abc', :name => 'Awesome Dude', :email => 'awesome@example.com', :info => {:name => 'DUUUUDE!'}, :persisted? => true)
92
+ MockIdentity.should_receive(:create).with(properties).and_return(m)
93
+ end
94
+
95
+ it 'should set the auth hash' do
96
+ post '/auth/identity/register', properties
97
+ auth_hash['uid'].should == 'abc'
98
+ end
99
+ end
100
+
101
+ context 'with invalid identity' do
102
+ let(:properties) { {
103
+ :name => 'Awesome Dude',
104
+ :email => 'awesome@example.com',
105
+ :password => 'NOT',
106
+ :password_confirmation => 'MATCHING'
107
+ } }
108
+
109
+ before do
110
+ MockIdentity.should_receive(:create).with(properties).and_return(mock(:persisted? => false))
111
+ end
112
+
113
+ context 'default' do
114
+ it 'should show registration form' do
115
+ post '/auth/identity/register', properties
116
+ last_response.body.should be_include("Register Identity")
117
+ end
118
+ end
119
+
120
+ context 'custom on_failed_registration endpoint' do
121
+ it 'should set the identity hash' do
122
+ set_app!(:on_failed_registration => lambda{|env| [404, {'env' => env}, ["HELLO!"]]}) do
123
+ post '/auth/identity/register', properties
124
+ identity_hash.should_not be_nil
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup :default, :development, :test
4
+
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+
8
+ require 'rack/test'
9
+ require 'omniauth/identity'
10
+
11
+ RSpec.configure do |config|
12
+ config.include Rack::Test::Methods
13
+ end
14
+
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth-identity
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.beta1
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Michael Bleigh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-19 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: omniauth
16
+ requirement: &70239729775760 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0.beta1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70239729775760
25
+ - !ruby/object:Gem::Dependency
26
+ name: maruku
27
+ requirement: &70239729775260 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '0.6'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70239729775260
36
+ - !ruby/object:Gem::Dependency
37
+ name: simplecov
38
+ requirement: &70239729774800 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '0.4'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70239729774800
47
+ - !ruby/object:Gem::Dependency
48
+ name: rack-test
49
+ requirement: &70239729774340 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.5'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70239729774340
58
+ - !ruby/object:Gem::Dependency
59
+ name: rake
60
+ requirement: &70239729790260 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '0.8'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70239729790260
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &70239729789800 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '2.5'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70239729789800
80
+ - !ruby/object:Gem::Dependency
81
+ name: bcrypt-ruby
82
+ requirement: &70239729789340 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: 2.1.4
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *70239729789340
91
+ - !ruby/object:Gem::Dependency
92
+ name: activerecord
93
+ requirement: &70239729788880 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: '3.0'
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *70239729788880
102
+ description: Internal authentication handlers for OmniAuth.
103
+ email:
104
+ - michael@intridea.com
105
+ executables: []
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - .gitignore
110
+ - .rspec
111
+ - Gemfile
112
+ - Gemfile.lock
113
+ - Guardfile
114
+ - README.markdown
115
+ - Rakefile
116
+ - lib/omniauth-identity.rb
117
+ - lib/omniauth-identity/version.rb
118
+ - lib/omniauth/identity.rb
119
+ - lib/omniauth/identity/model.rb
120
+ - lib/omniauth/identity/models/active_record.rb
121
+ - lib/omniauth/identity/secure_password.rb
122
+ - lib/omniauth/strategies/identity.rb
123
+ - omniauth-identity.gemspec
124
+ - spec/omniauth/identity/model_spec.rb
125
+ - spec/omniauth/identity/models/active_record_spec.rb
126
+ - spec/omniauth/identity/secure_password_spec.rb
127
+ - spec/omniauth/strategies/identity_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: http://github.com/intridea/omniauth-identity
130
+ licenses: []
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: 1.3.6
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 1.8.10
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: Internal authentication handlers for OmniAuth.
153
+ test_files:
154
+ - spec/omniauth/identity/model_spec.rb
155
+ - spec/omniauth/identity/models/active_record_spec.rb
156
+ - spec/omniauth/identity/secure_password_spec.rb
157
+ - spec/omniauth/strategies/identity_spec.rb
158
+ - spec/spec_helper.rb