omniauth-identity 1.1.1 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +81 -0
- data/CODE_OF_CONDUCT.md +133 -0
- data/LICENSE +22 -0
- data/README.md +238 -0
- data/lib/omniauth-identity.rb +2 -0
- data/lib/omniauth-identity/version.rb +3 -1
- data/lib/omniauth/identity.rb +3 -2
- data/lib/omniauth/identity/model.rb +17 -14
- data/lib/omniauth/identity/models/active_record.rb +4 -1
- data/lib/omniauth/identity/models/couch_potato.rb +3 -4
- data/lib/omniauth/identity/models/mongoid.rb +3 -7
- data/lib/omniauth/identity/models/{mongo_mapper.rb → no_brainer.rb} +6 -4
- data/lib/omniauth/identity/secure_password.rb +4 -4
- data/lib/omniauth/strategies/identity.rb +92 -39
- data/spec/omniauth/identity/model_spec.rb +60 -59
- data/spec/omniauth/identity/models/active_record_spec.rb +24 -8
- data/spec/omniauth/identity/models/couch_potato_spec.rb +17 -11
- data/spec/omniauth/identity/models/mongoid_spec.rb +23 -13
- data/spec/omniauth/identity/models/no_brainer_spec.rb +17 -0
- data/spec/omniauth/identity/secure_password_spec.rb +12 -12
- data/spec/omniauth/strategies/identity_spec.rb +178 -67
- data/spec/spec_helper.rb +20 -6
- metadata +75 -128
- data/.gitignore +0 -4
- data/.rspec +0 -2
- data/Gemfile +0 -11
- data/Gemfile.lock +0 -179
- data/Guardfile +0 -10
- data/README.markdown +0 -202
- data/Rakefile +0 -9
- data/lib/omniauth/identity/models/data_mapper.rb +0 -32
- data/omniauth-identity.gemspec +0 -32
- data/spec/omniauth/identity/models/data_mapper_spec.rb +0 -22
- data/spec/omniauth/identity/models/mongo_mapper_spec.rb +0 -15
data/lib/omniauth-identity.rb
CHANGED
data/lib/omniauth/identity.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'omniauth'
|
2
4
|
|
3
5
|
module OmniAuth
|
@@ -10,10 +12,9 @@ module OmniAuth
|
|
10
12
|
autoload :SecurePassword, 'omniauth/identity/secure_password'
|
11
13
|
module Models
|
12
14
|
autoload :ActiveRecord, 'omniauth/identity/models/active_record'
|
13
|
-
autoload :MongoMapper, 'omniauth/identity/models/mongo_mapper'
|
14
15
|
autoload :Mongoid, 'omniauth/identity/models/mongoid'
|
15
|
-
autoload :DataMapper, 'omniauth/identity/models/data_mapper'
|
16
16
|
autoload :CouchPotatoModule, 'omniauth/identity/models/couch_potato'
|
17
|
+
autoload :NoBrainer, 'omniauth/identity/models/no_brainer'
|
17
18
|
end
|
18
19
|
end
|
19
20
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OmniAuth
|
2
4
|
module Identity
|
3
5
|
# This module provides an includable interface for implementing the
|
@@ -28,6 +30,7 @@ module OmniAuth
|
|
28
30
|
def authenticate(conditions, password)
|
29
31
|
instance = locate(conditions)
|
30
32
|
return false unless instance
|
33
|
+
|
31
34
|
instance.authenticate(password)
|
32
35
|
end
|
33
36
|
|
@@ -36,7 +39,7 @@ module OmniAuth
|
|
36
39
|
# @return [String] The method name.
|
37
40
|
def auth_key(method = false)
|
38
41
|
@auth_key = method.to_s unless method == false
|
39
|
-
@auth_key = nil if @auth_key == ''
|
42
|
+
@auth_key = nil if !defined?(@auth_key) || @auth_key == ''
|
40
43
|
|
41
44
|
@auth_key || 'email'
|
42
45
|
end
|
@@ -52,22 +55,20 @@ module OmniAuth
|
|
52
55
|
raise NotImplementedError
|
53
56
|
end
|
54
57
|
|
55
|
-
SCHEMA_ATTRIBUTES = %w
|
58
|
+
SCHEMA_ATTRIBUTES = %w[name email nickname first_name last_name location description image phone].freeze
|
56
59
|
# A hash of as much of the standard OmniAuth schema as is stored
|
57
60
|
# in this particular model. By default, this will call instance
|
58
61
|
# methods for each of the attributes it needs in turn, ignoring
|
59
62
|
# any for which `#respond_to?` is `false`.
|
60
63
|
#
|
61
|
-
# If `first_name`, `nickname`, and/or `last_name` is provided but
|
64
|
+
# If `first_name`, `nickname`, and/or `last_name` is provided but
|
62
65
|
# `name` is not, it will be automatically calculated.
|
63
66
|
#
|
64
67
|
# @return [Hash] A string-keyed hash of user information.
|
65
68
|
def info
|
66
|
-
|
69
|
+
SCHEMA_ATTRIBUTES.each_with_object({}) do |attribute, hash|
|
67
70
|
hash[attribute] = send(attribute) if respond_to?(attribute)
|
68
|
-
hash
|
69
71
|
end
|
70
|
-
info
|
71
72
|
end
|
72
73
|
|
73
74
|
# An identifying string that must be globally unique to the
|
@@ -75,22 +76,23 @@ module OmniAuth
|
|
75
76
|
#
|
76
77
|
# @return [String] An identifier string unique to this identity.
|
77
78
|
def uid
|
78
|
-
if respond_to?(
|
79
|
-
return nil if
|
80
|
-
|
79
|
+
if respond_to?(:id)
|
80
|
+
return nil if id.nil?
|
81
|
+
|
82
|
+
id.to_s
|
81
83
|
else
|
82
|
-
raise NotImplementedError
|
84
|
+
raise NotImplementedError
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
86
88
|
# Used to retrieve the user-supplied authentication key (e.g. a
|
87
89
|
# username or email). Determined using the class method of the same name,
|
88
|
-
# defaults to `:email`.
|
90
|
+
# defaults to `:email`.
|
89
91
|
#
|
90
92
|
# @return [String] An identifying string that will be entered by
|
91
93
|
# users upon sign in.
|
92
94
|
def auth_key
|
93
|
-
if respond_to?(self.class.auth_key)
|
95
|
+
if respond_to?(self.class.auth_key.to_sym)
|
94
96
|
send(self.class.auth_key)
|
95
97
|
else
|
96
98
|
raise NotImplementedError
|
@@ -104,8 +106,9 @@ module OmniAuth
|
|
104
106
|
# @param [String] value The value to which the auth key should be
|
105
107
|
# set.
|
106
108
|
def auth_key=(value)
|
107
|
-
|
108
|
-
|
109
|
+
auth_key_setter = "#{self.class.auth_key}=".to_sym
|
110
|
+
if respond_to?(auth_key_setter)
|
111
|
+
send(auth_key_setter, value)
|
109
112
|
else
|
110
113
|
raise NotImplementedError
|
111
114
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
|
3
5
|
module OmniAuth
|
@@ -12,10 +14,11 @@ module OmniAuth
|
|
12
14
|
|
13
15
|
def self.auth_key=(key)
|
14
16
|
super
|
15
|
-
validates_uniqueness_of key, :
|
17
|
+
validates_uniqueness_of key, case_sensitive: false
|
16
18
|
end
|
17
19
|
|
18
20
|
def self.locate(search_hash)
|
21
|
+
search_hash = search_hash.reverse_merge!('provider' => 'identity') if column_names.include?('provider')
|
19
22
|
where(search_hash).first
|
20
23
|
end
|
21
24
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'couch_potato'
|
2
4
|
|
3
5
|
module OmniAuth
|
@@ -5,11 +7,8 @@ module OmniAuth
|
|
5
7
|
module Models
|
6
8
|
# can not be named CouchPotato since there is a class with that name
|
7
9
|
module CouchPotatoModule
|
8
|
-
|
9
10
|
def self.included(base)
|
10
|
-
|
11
11
|
base.class_eval do
|
12
|
-
|
13
12
|
include ::OmniAuth::Identity::Model
|
14
13
|
include ::OmniAuth::Identity::SecurePassword
|
15
14
|
|
@@ -17,7 +16,7 @@ module OmniAuth
|
|
17
16
|
|
18
17
|
def self.auth_key=(key)
|
19
18
|
super
|
20
|
-
validates_uniqueness_of key, :
|
19
|
+
validates_uniqueness_of key, case_sensitive: false
|
21
20
|
end
|
22
21
|
|
23
22
|
def self.locate(search_hash)
|
@@ -1,14 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'mongoid'
|
2
4
|
|
3
5
|
module OmniAuth
|
4
6
|
module Identity
|
5
7
|
module Models
|
6
8
|
module Mongoid
|
7
|
-
|
8
9
|
def self.included(base)
|
9
|
-
|
10
10
|
base.class_eval do
|
11
|
-
|
12
11
|
include ::OmniAuth::Identity::Model
|
13
12
|
include ::OmniAuth::Identity::SecurePassword
|
14
13
|
|
@@ -16,17 +15,14 @@ module OmniAuth
|
|
16
15
|
|
17
16
|
def self.auth_key=(key)
|
18
17
|
super
|
19
|
-
validates_uniqueness_of key, :
|
18
|
+
validates_uniqueness_of key, case_sensitive: false
|
20
19
|
end
|
21
20
|
|
22
21
|
def self.locate(search_hash)
|
23
22
|
where(search_hash).first
|
24
23
|
end
|
25
|
-
|
26
24
|
end
|
27
|
-
|
28
25
|
end
|
29
|
-
|
30
26
|
end
|
31
27
|
end
|
32
28
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'nobrainer'
|
2
4
|
|
3
5
|
module OmniAuth
|
4
6
|
module Identity
|
5
7
|
module Models
|
6
|
-
|
8
|
+
# http://nobrainer.io/ an ORM for RethinkDB
|
9
|
+
module NoBrainer
|
7
10
|
def self.included(base)
|
8
11
|
base.class_eval do
|
9
12
|
include ::OmniAuth::Identity::Model
|
@@ -13,7 +16,7 @@ module OmniAuth
|
|
13
16
|
|
14
17
|
def self.auth_key=(key)
|
15
18
|
super
|
16
|
-
validates_uniqueness_of key, :
|
19
|
+
validates_uniqueness_of key, case_sensitive: false
|
17
20
|
end
|
18
21
|
|
19
22
|
def self.locate(search_hash)
|
@@ -25,4 +28,3 @@ module OmniAuth
|
|
25
28
|
end
|
26
29
|
end
|
27
30
|
end
|
28
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bcrypt'
|
2
4
|
|
3
5
|
module OmniAuth
|
@@ -9,9 +11,7 @@ module OmniAuth
|
|
9
11
|
# a has_secure_password method.
|
10
12
|
module SecurePassword
|
11
13
|
def self.included(base)
|
12
|
-
unless base.respond_to?(:has_secure_password)
|
13
|
-
base.extend ClassMethods
|
14
|
-
end
|
14
|
+
base.extend ClassMethods unless base.respond_to?(:has_secure_password)
|
15
15
|
end
|
16
16
|
|
17
17
|
module ClassMethods
|
@@ -40,7 +40,7 @@ module OmniAuth
|
|
40
40
|
# User.find_by_name("david").try(:authenticate, "notright") # => nil
|
41
41
|
# User.find_by_name("david").try(:authenticate, "mUc3m00RsqyRe") # => user
|
42
42
|
def has_secure_password
|
43
|
-
attr_reader
|
43
|
+
attr_reader :password
|
44
44
|
|
45
45
|
validates_confirmation_of :password
|
46
46
|
validates_presence_of :password_digest
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OmniAuth
|
2
4
|
module Strategies
|
3
5
|
# The identity strategy allows you to provide simple internal
|
@@ -6,76 +8,91 @@ module OmniAuth
|
|
6
8
|
class Identity
|
7
9
|
include OmniAuth::Strategy
|
8
10
|
|
9
|
-
option :fields, [
|
10
|
-
|
11
|
-
|
12
|
-
option :
|
13
|
-
option :
|
11
|
+
option :fields, %i[name email]
|
12
|
+
|
13
|
+
# Primary Feature Switches:
|
14
|
+
option :enable_registration, true # See #other_phase and #request_phase
|
15
|
+
option :enable_login, true # See #other_phase
|
16
|
+
|
17
|
+
# Customization Options:
|
18
|
+
option :on_login, nil # See #request_phase
|
19
|
+
option :on_validation, nil # See #registration_phase
|
20
|
+
option :on_registration, nil # See #registration_phase
|
21
|
+
option :on_failed_registration, nil # See #registration_phase
|
22
|
+
option :locate_conditions, ->(req) { { model.auth_key => req['auth_key'] } }
|
14
23
|
|
15
24
|
def request_phase
|
16
25
|
if options[:on_login]
|
17
|
-
options[:on_login].call(
|
26
|
+
options[:on_login].call(env)
|
18
27
|
else
|
19
|
-
|
20
|
-
:title => (options[:title] || "Identity Verification"),
|
21
|
-
:url => callback_path
|
22
|
-
) do |f|
|
23
|
-
f.text_field 'Login', 'auth_key'
|
24
|
-
f.password_field 'Password', 'password'
|
25
|
-
f.html "<p align='center'><a href='#{registration_path}'>Create an Identity</a></p>"
|
26
|
-
end.to_response
|
28
|
+
build_omniauth_login_form.to_response
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
32
|
def callback_phase
|
31
33
|
return fail!(:invalid_credentials) unless identity
|
34
|
+
|
32
35
|
super
|
33
36
|
end
|
34
37
|
|
35
38
|
def other_phase
|
36
|
-
if on_registration_path?
|
39
|
+
if options[:enable_registration] && on_registration_path?
|
37
40
|
if request.get?
|
38
41
|
registration_form
|
39
42
|
elsif request.post?
|
40
43
|
registration_phase
|
44
|
+
else
|
45
|
+
call_app!
|
41
46
|
end
|
47
|
+
elsif options[:enable_login] && on_request_path?
|
48
|
+
# OmniAuth, by default, disables "GET" requests for security reasons.
|
49
|
+
# This effectively disables omniauth-identity tool's login form feature.
|
50
|
+
# Because it is disabled by default, and because enabling it would desecuritize all the other
|
51
|
+
# OmniAuth strategies that may be implemented, we do not ask users to modify that setting.
|
52
|
+
# Instead we hook in here in the "other_phase", with a config setting of our own: `enable_login`
|
53
|
+
request_phase
|
42
54
|
else
|
43
55
|
call_app!
|
44
56
|
end
|
45
57
|
end
|
46
58
|
|
47
|
-
def registration_form
|
59
|
+
def registration_form(validation_message = nil)
|
48
60
|
if options[:on_registration]
|
49
|
-
options[:on_registration].call(
|
61
|
+
options[:on_registration].call(env)
|
50
62
|
else
|
51
|
-
|
52
|
-
options[:fields].each do |field|
|
53
|
-
f.text_field field.to_s.capitalize, field.to_s
|
54
|
-
end
|
55
|
-
f.password_field 'Password', 'password'
|
56
|
-
f.password_field 'Confirm Password', 'password_confirmation'
|
57
|
-
end.to_response
|
63
|
+
build_omniauth_registration_form(validation_message).to_response
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
61
67
|
def registration_phase
|
62
|
-
attributes = (options[:fields] + [
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
+
attributes = (options[:fields] + %i[password password_confirmation]).each_with_object({}) do |k, h|
|
69
|
+
h[k] = request[k.to_s]
|
70
|
+
end
|
71
|
+
if model.respond_to?(:column_names) && model.column_names.include?('provider')
|
72
|
+
attributes.reverse_merge!(provider: 'identity')
|
73
|
+
end
|
74
|
+
@identity = model.new(attributes)
|
75
|
+
|
76
|
+
# on_validation may run a Captcha or other validation mechanism
|
77
|
+
# Must return true when validation passes, false otherwise
|
78
|
+
if options[:on_validation] && !options[:on_validation].call(env: env)
|
68
79
|
if options[:on_failed_registration]
|
69
|
-
|
70
|
-
options[:on_failed_registration].call(
|
80
|
+
env['omniauth.identity'] = @identity
|
81
|
+
options[:on_failed_registration].call(env)
|
71
82
|
else
|
72
|
-
|
83
|
+
validation_message = 'Validation failed'
|
84
|
+
registration_form(validation_message)
|
73
85
|
end
|
86
|
+
elsif @identity.save && @identity.persisted?
|
87
|
+
env['PATH_INFO'] = callback_path
|
88
|
+
callback_phase
|
89
|
+
else
|
90
|
+
show_custom_options_or_default
|
74
91
|
end
|
75
92
|
end
|
76
93
|
|
77
|
-
uid{ identity.uid }
|
78
|
-
info{ identity.info }
|
94
|
+
uid { identity.uid }
|
95
|
+
info { identity.info }
|
79
96
|
|
80
97
|
def registration_path
|
81
98
|
options[:registration_path] || "#{path_prefix}/#{name}/register"
|
@@ -86,18 +103,54 @@ module OmniAuth
|
|
86
103
|
end
|
87
104
|
|
88
105
|
def identity
|
89
|
-
if options
|
90
|
-
conditions = instance_exec(request, &options
|
106
|
+
if options[:locate_conditions].is_a? Proc
|
107
|
+
conditions = instance_exec(request, &options[:locate_conditions])
|
91
108
|
conditions.to_hash
|
92
109
|
else
|
93
|
-
conditions = options
|
110
|
+
conditions = options[:locate_conditions].to_hash
|
94
111
|
end
|
95
|
-
@identity ||= model.authenticate(conditions, request['password']
|
112
|
+
@identity ||= model.authenticate(conditions, request['password'])
|
96
113
|
end
|
97
114
|
|
98
115
|
def model
|
99
116
|
options[:model] || ::Identity
|
100
117
|
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def build_omniauth_login_form
|
122
|
+
OmniAuth::Form.build(
|
123
|
+
title: (options[:title] || 'Identity Verification'),
|
124
|
+
url: callback_path
|
125
|
+
) do |f|
|
126
|
+
f.text_field 'Login', 'auth_key'
|
127
|
+
f.password_field 'Password', 'password'
|
128
|
+
if options[:enable_registration]
|
129
|
+
f.html "<p align='center'><a href='#{registration_path}'>Create an Identity</a></p>"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def build_omniauth_registration_form(validation_message)
|
135
|
+
OmniAuth::Form.build(title: 'Register Identity') do |f|
|
136
|
+
f.html "<p style='color:red'>#{validation_message}</p>" if validation_message
|
137
|
+
options[:fields].each do |field|
|
138
|
+
f.text_field field.to_s.capitalize, field.to_s
|
139
|
+
end
|
140
|
+
f.password_field 'Password', 'password'
|
141
|
+
f.password_field 'Confirm Password', 'password_confirmation'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def show_custom_options_or_default
|
146
|
+
if options[:on_failed_registration]
|
147
|
+
env['omniauth.identity'] = @identity
|
148
|
+
options[:on_failed_registration].call(env)
|
149
|
+
else
|
150
|
+
validation_message = 'One or more fields were invalid'
|
151
|
+
registration_form(validation_message)
|
152
|
+
end
|
153
|
+
end
|
101
154
|
end
|
102
155
|
end
|
103
156
|
end
|