sorcery 0.8.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sorcery might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +75 -14
- data/CHANGELOG.md +23 -1
- data/Gemfile +1 -0
- data/README.md +137 -86
- data/gemfiles/active_record-rails40.gemfile +7 -0
- data/gemfiles/active_record-rails41.gemfile +3 -2
- data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
- data/gemfiles/mongo_mapper-rails41.gemfile +2 -1
- data/gemfiles/mongoid-rails40.gemfile +9 -0
- data/gemfiles/mongoid-rails41.gemfile +3 -5
- data/gemfiles/mongoid3-rails32.gemfile +9 -0
- data/lib/generators/sorcery/USAGE +1 -1
- data/lib/generators/sorcery/install_generator.rb +19 -5
- data/lib/generators/sorcery/templates/initializer.rb +34 -9
- data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -1
- data/lib/generators/sorcery/templates/migration/core.rb +2 -2
- data/lib/generators/sorcery/templates/migration/external.rb +3 -1
- data/lib/sorcery.rb +75 -43
- data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
- data/lib/sorcery/adapters/base_adapter.rb +30 -0
- data/lib/sorcery/adapters/data_mapper_adapter.rb +176 -0
- data/lib/sorcery/adapters/mongo_mapper_adapter.rb +110 -0
- data/lib/sorcery/adapters/mongoid_adapter.rb +97 -0
- data/lib/sorcery/controller.rb +5 -64
- data/lib/sorcery/controller/config.rb +65 -0
- data/lib/sorcery/controller/submodules/activity_logging.rb +16 -21
- data/lib/sorcery/controller/submodules/brute_force_protection.rb +6 -6
- data/lib/sorcery/controller/submodules/external.rb +8 -28
- data/lib/sorcery/controller/submodules/remember_me.rb +4 -4
- data/lib/sorcery/controller/submodules/session_timeout.rb +10 -6
- data/lib/sorcery/model.rb +43 -175
- data/lib/sorcery/model/config.rb +96 -0
- data/lib/sorcery/model/submodules/activity_logging.rb +29 -36
- data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -37
- data/lib/sorcery/model/submodules/external.rb +53 -9
- data/lib/sorcery/model/submodules/remember_me.rb +12 -31
- data/lib/sorcery/model/submodules/reset_password.rb +21 -39
- data/lib/sorcery/model/submodules/user_activation.rb +21 -63
- data/lib/sorcery/model/temporary_token.rb +4 -4
- data/lib/sorcery/providers/base.rb +11 -0
- data/lib/sorcery/providers/facebook.rb +1 -1
- data/lib/sorcery/providers/github.rb +1 -1
- data/lib/sorcery/providers/google.rb +1 -1
- data/lib/sorcery/providers/heroku.rb +57 -0
- data/lib/sorcery/providers/jira.rb +77 -0
- data/lib/sorcery/providers/linkedin.rb +1 -1
- data/lib/sorcery/providers/liveid.rb +1 -1
- data/lib/sorcery/providers/salesforce.rb +50 -0
- data/lib/sorcery/providers/twitter.rb +1 -1
- data/lib/sorcery/providers/vk.rb +6 -4
- data/lib/sorcery/providers/xing.rb +1 -1
- data/lib/sorcery/test_helpers/internal.rb +7 -3
- data/lib/sorcery/test_helpers/rails/controller.rb +5 -1
- data/lib/sorcery/version.rb +3 -0
- data/sorcery.gemspec +6 -2
- data/spec/active_record/user_activity_logging_spec.rb +9 -0
- data/spec/controllers/controller_activity_logging_spec.rb +124 -0
- data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
- data/spec/{active_record → controllers}/controller_http_basic_auth_spec.rb +14 -11
- data/spec/{active_record → controllers}/controller_oauth2_spec.rb +128 -56
- data/spec/{active_record → controllers}/controller_oauth_spec.rb +94 -70
- data/spec/{active_record → controllers}/controller_remember_me_spec.rb +32 -12
- data/spec/{active_record → controllers}/controller_session_timeout_spec.rb +15 -5
- data/spec/{shared_examples/controller_shared_examples.rb → controllers/controller_spec.rb} +34 -19
- data/spec/{datamapper → data_mapper}/user_activation_spec.rb +1 -1
- data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
- data/spec/{datamapper → data_mapper}/user_brute_force_protection_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_oauth_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_remember_me_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_reset_password_spec.rb +1 -1
- data/spec/{datamapper → data_mapper}/user_spec.rb +1 -1
- data/spec/mongoid/user_spec.rb +13 -0
- data/spec/orm/active_record.rb +12 -0
- data/spec/orm/{datamapper.rb → data_mapper.rb} +16 -2
- data/spec/orm/mongo_mapper.rb +0 -1
- data/spec/orm/mongoid.rb +4 -0
- data/spec/rails_app/app/controllers/sorcery_controller.rb +62 -1
- data/spec/rails_app/app/{datamapper → data_mapper}/authentication.rb +0 -0
- data/spec/rails_app/app/{datamapper → data_mapper}/user.rb +0 -0
- data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
- data/spec/rails_app/config/routes.rb +9 -0
- data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
- data/spec/shared_examples/user_activation_shared_examples.rb +7 -7
- data/spec/shared_examples/user_activity_logging_shared_examples.rb +73 -5
- data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +127 -9
- data/spec/shared_examples/user_oauth_shared_examples.rb +3 -6
- data/spec/shared_examples/user_remember_me_shared_examples.rb +6 -3
- data/spec/shared_examples/user_reset_password_shared_examples.rb +10 -10
- data/spec/shared_examples/user_shared_examples.rb +117 -30
- data/spec/spec_helper.rb +7 -22
- metadata +36 -58
- data/Gemfile.rails4 +0 -22
- data/VERSION +0 -1
- data/lib/sorcery/model/adapters/active_record.rb +0 -54
- data/lib/sorcery/model/adapters/datamapper.rb +0 -123
- data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -60
- data/lib/sorcery/model/adapters/mongoid.rb +0 -88
- data/lib/sorcery/test_helpers/rails.rb +0 -7
- data/spec/active_record/controller_activity_logging_spec.rb +0 -29
- data/spec/active_record/controller_brute_force_protection_spec.rb +0 -158
- data/spec/active_record/controller_spec.rb +0 -8
- data/spec/active_record/integration_spec.rb +0 -23
- data/spec/datamapper/controller_activity_logging_spec.rb +0 -17
- data/spec/datamapper/controller_spec.rb +0 -8
- data/spec/datamapper/user_activity_logging_spec.rb +0 -9
- data/spec/mongo_mapper/controller_spec.rb +0 -8
- data/spec/mongoid/controller_activity_logging_spec.rb +0 -16
- data/spec/mongoid/controller_spec.rb +0 -8
- data/spec/rails_app/public/404.html +0 -26
- data/spec/rails_app/public/422.html +0 -26
- data/spec/rails_app/public/500.html +0 -26
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/images/rails.png +0 -0
- data/spec/rails_app/public/javascripts/application.js +0 -2
- data/spec/rails_app/public/javascripts/controls.js +0 -965
- data/spec/rails_app/public/javascripts/dragdrop.js +0 -974
- data/spec/rails_app/public/javascripts/effects.js +0 -1123
- data/spec/rails_app/public/javascripts/prototype.js +0 -6001
- data/spec/rails_app/public/javascripts/rails.js +0 -175
- data/spec/rails_app/public/robots.txt +0 -5
- data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
- data/spec/shared_examples/controller_activity_logging_shared_examples.rb +0 -125
- data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -52
- data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -62
@@ -50,13 +50,7 @@ module Sorcery
|
|
50
50
|
base.extend(ClassMethods)
|
51
51
|
|
52
52
|
base.sorcery_config.after_config << :validate_mailer_defined
|
53
|
-
base.sorcery_config.after_config << :
|
54
|
-
if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
|
55
|
-
base.sorcery_config.after_config << :define_reset_password_mongo_mapper_fields
|
56
|
-
end
|
57
|
-
if defined?(DataMapper) and base.ancestors.include?(DataMapper::Resource)
|
58
|
-
base.sorcery_config.after_config << :define_reset_password_datamapper_fields
|
59
|
-
end
|
53
|
+
base.sorcery_config.after_config << :define_reset_password_fields
|
60
54
|
|
61
55
|
base.send(:include, InstanceMethods)
|
62
56
|
|
@@ -80,45 +74,33 @@ module Sorcery
|
|
80
74
|
raise ArgumentError, msg if @sorcery_config.reset_password_mailer == nil and @sorcery_config.reset_password_mailer_disabled == false
|
81
75
|
end
|
82
76
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
77
|
+
def define_reset_password_fields
|
78
|
+
sorcery_adapter.define_field sorcery_config.reset_password_token_attribute_name, String
|
79
|
+
sorcery_adapter.define_field sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
80
|
+
sorcery_adapter.define_field sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
87
81
|
end
|
88
82
|
|
89
|
-
def define_reset_password_mongo_mapper_fields
|
90
|
-
key sorcery_config.reset_password_token_attribute_name, String
|
91
|
-
key sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
92
|
-
key sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
93
|
-
end
|
94
|
-
|
95
|
-
def define_reset_password_datamapper_fields
|
96
|
-
property sorcery_config.reset_password_token_attribute_name, String
|
97
|
-
property sorcery_config.reset_password_token_expires_at_attribute_name, Time
|
98
|
-
property sorcery_config.reset_password_email_sent_at_attribute_name, Time
|
99
|
-
[sorcery_config.reset_password_token_expires_at_attribute_name,
|
100
|
-
sorcery_config.reset_password_email_sent_at_attribute_name].each do |sym|
|
101
|
-
alias_method "orig_#{sym}", sym
|
102
|
-
define_method(sym) do
|
103
|
-
t = send("orig_#{sym}")
|
104
|
-
t && Time.new(t.year, t.month, t.day, t.hour, t.min, t.sec, 0)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
83
|
end
|
109
84
|
|
110
85
|
module InstanceMethods
|
111
|
-
# generates a reset code with expiration
|
112
|
-
def
|
86
|
+
# generates a reset code with expiration
|
87
|
+
def generate_reset_password_token!
|
113
88
|
config = sorcery_config
|
114
|
-
# hammering protection
|
115
|
-
return false if config.reset_password_time_between_emails && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.ago.utc
|
116
89
|
attributes = {config.reset_password_token_attribute_name => TemporaryToken.generate_random_token,
|
117
90
|
config.reset_password_email_sent_at_attribute_name => Time.now.in_time_zone}
|
118
91
|
attributes[config.reset_password_token_expires_at_attribute_name] = Time.now.in_time_zone + config.reset_password_expiration_period if config.reset_password_expiration_period
|
119
|
-
|
120
|
-
|
121
|
-
|
92
|
+
|
93
|
+
self.sorcery_adapter.update_attributes(attributes)
|
94
|
+
end
|
95
|
+
|
96
|
+
# generates a reset code with expiration and sends an email to the user.
|
97
|
+
def deliver_reset_password_instructions!
|
98
|
+
config = sorcery_config
|
99
|
+
# hammering protection
|
100
|
+
return false if config.reset_password_time_between_emails.present? && self.send(config.reset_password_email_sent_at_attribute_name) && self.send(config.reset_password_email_sent_at_attribute_name) > config.reset_password_time_between_emails.seconds.ago.utc
|
101
|
+
self.class.sorcery_adapter.transaction do
|
102
|
+
generate_reset_password_token!
|
103
|
+
send_reset_password_email! unless config.reset_password_mailer_disabled
|
122
104
|
end
|
123
105
|
end
|
124
106
|
|
@@ -126,11 +108,11 @@ module Sorcery
|
|
126
108
|
def change_password!(new_password)
|
127
109
|
clear_reset_password_token
|
128
110
|
self.send(:"#{sorcery_config.password_attribute_name}=", new_password)
|
129
|
-
|
111
|
+
sorcery_adapter.save
|
130
112
|
end
|
131
113
|
|
132
114
|
protected
|
133
|
-
|
115
|
+
|
134
116
|
def send_reset_password_email!
|
135
117
|
generic_send_email(:reset_password_email_method_name, :reset_password_mailer)
|
136
118
|
end
|
@@ -15,7 +15,7 @@ module Sorcery
|
|
15
15
|
# (sent by email).
|
16
16
|
|
17
17
|
:activation_token_expires_at_attribute_name, # the attribute name to hold activation code
|
18
|
-
# expiration date.
|
18
|
+
# expiration date.
|
19
19
|
|
20
20
|
:activation_token_expiration_period, # how many seconds before the activation code
|
21
21
|
# expires. nil for never expires.
|
@@ -51,33 +51,14 @@ module Sorcery
|
|
51
51
|
end
|
52
52
|
|
53
53
|
base.class_eval do
|
54
|
-
if
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
after :create do
|
61
|
-
if send_activation_needed_email?
|
62
|
-
send_activation_needed_email!
|
63
|
-
end
|
64
|
-
end
|
65
|
-
else
|
66
|
-
# don't setup activation if no password supplied - this user is created automatically
|
67
|
-
before_create :setup_activation, :if => Proc.new { |user| user.send(sorcery_config.password_attribute_name).present? }
|
68
|
-
# don't send activation needed email if no crypted password created - this user is external (OAuth etc.)
|
69
|
-
after_create :send_activation_needed_email!, :if => :send_activation_needed_email?
|
70
|
-
end
|
54
|
+
# don't setup activation if no password supplied - this user is created automatically
|
55
|
+
sorcery_adapter.define_callback :before, :create, :setup_activation, :if => Proc.new { |user| user.send(sorcery_config.password_attribute_name).present? }
|
56
|
+
# don't send activation needed email if no crypted password created - this user is external (OAuth etc.)
|
57
|
+
sorcery_adapter.define_callback :after, :create, :send_activation_needed_email!, :if => :send_activation_needed_email?
|
71
58
|
end
|
72
59
|
|
73
60
|
base.sorcery_config.after_config << :validate_mailer_defined
|
74
|
-
base.sorcery_config.after_config << :
|
75
|
-
if defined?(MongoMapper) and base.ancestors.include?(MongoMapper::Document)
|
76
|
-
base.sorcery_config.after_config << :define_user_activation_mongo_mapper_fields
|
77
|
-
end
|
78
|
-
if defined?(DataMapper) and base.ancestors.include?(DataMapper::Resource)
|
79
|
-
base.sorcery_config.after_config << :define_user_activation_datamapper_fields
|
80
|
-
end
|
61
|
+
base.sorcery_config.after_config << :define_user_activation_fields
|
81
62
|
base.sorcery_config.before_authenticate << :prevent_non_active_login
|
82
63
|
|
83
64
|
base.extend(ClassMethods)
|
@@ -104,58 +85,35 @@ module Sorcery
|
|
104
85
|
raise ArgumentError, msg if @sorcery_config.user_activation_mailer == nil and @sorcery_config.activation_mailer_disabled == false
|
105
86
|
end
|
106
87
|
|
107
|
-
def
|
108
|
-
self.class_eval do
|
109
|
-
field sorcery_config.activation_state_attribute_name, :type => String
|
110
|
-
field sorcery_config.activation_token_attribute_name, :type => String
|
111
|
-
field sorcery_config.activation_token_expires_at_attribute_name, :type => Time
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def define_user_activation_mongo_mapper_fields
|
88
|
+
def define_user_activation_fields
|
116
89
|
self.class_eval do
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def define_user_activation_datamapper_fields
|
124
|
-
self.class_eval do
|
125
|
-
property sorcery_config.activation_state_attribute_name, String
|
126
|
-
property sorcery_config.activation_token_attribute_name, String
|
127
|
-
property sorcery_config.activation_token_expires_at_attribute_name, Time
|
128
|
-
[sorcery_config.activation_token_expires_at_attribute_name].each do |sym|
|
129
|
-
alias_method "orig_#{sym}", sym
|
130
|
-
define_method(sym) do
|
131
|
-
t = send("orig_#{sym}")
|
132
|
-
t && Time.new(t.year, t.month, t.day, t.hour, t.min, t.sec, 0)
|
133
|
-
end
|
134
|
-
end
|
90
|
+
sorcery_adapter.define_field sorcery_config.activation_state_attribute_name, String
|
91
|
+
sorcery_adapter.define_field sorcery_config.activation_token_attribute_name, String
|
92
|
+
sorcery_adapter.define_field sorcery_config.activation_token_expires_at_attribute_name, Time
|
135
93
|
end
|
136
94
|
end
|
137
95
|
end
|
138
96
|
|
139
97
|
module InstanceMethods
|
98
|
+
def setup_activation
|
99
|
+
config = sorcery_config
|
100
|
+
generated_activation_token = TemporaryToken.generate_random_token
|
101
|
+
self.send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
|
102
|
+
self.send(:"#{config.activation_state_attribute_name}=", "pending")
|
103
|
+
self.send(:"#{config.activation_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.activation_token_expiration_period) if config.activation_token_expiration_period
|
104
|
+
end
|
105
|
+
|
140
106
|
# clears activation code, sets the user as 'active' and optionaly sends a success email.
|
141
107
|
def activate!
|
142
108
|
config = sorcery_config
|
143
109
|
self.send(:"#{config.activation_token_attribute_name}=", nil)
|
144
110
|
self.send(:"#{config.activation_state_attribute_name}=", "active")
|
145
111
|
send_activation_success_email! if send_activation_success_email?
|
146
|
-
|
112
|
+
sorcery_adapter.save(:validate => false, :raise_on_failure => true)
|
147
113
|
end
|
148
114
|
|
149
115
|
protected
|
150
116
|
|
151
|
-
def setup_activation
|
152
|
-
config = sorcery_config
|
153
|
-
generated_activation_token = TemporaryToken.generate_random_token
|
154
|
-
self.send(:"#{config.activation_token_attribute_name}=", generated_activation_token)
|
155
|
-
self.send(:"#{config.activation_state_attribute_name}=", "pending")
|
156
|
-
self.send(:"#{config.activation_token_expires_at_attribute_name}=", Time.now.in_time_zone + config.activation_token_expiration_period) if config.activation_token_expiration_period
|
157
|
-
end
|
158
|
-
|
159
117
|
# called automatically after user initial creation.
|
160
118
|
def send_activation_needed_email!
|
161
119
|
generic_send_email(:activation_needed_email_method_name, :user_activation_mailer)
|
@@ -164,14 +122,14 @@ module Sorcery
|
|
164
122
|
def send_activation_success_email!
|
165
123
|
generic_send_email(:activation_success_email_method_name, :user_activation_mailer)
|
166
124
|
end
|
167
|
-
|
125
|
+
|
168
126
|
def send_activation_success_email?
|
169
127
|
!external? && (
|
170
128
|
!(sorcery_config.activation_success_email_method_name.nil? ||
|
171
129
|
sorcery_config.activation_mailer_disabled == true)
|
172
130
|
)
|
173
131
|
end
|
174
|
-
|
132
|
+
|
175
133
|
def send_activation_needed_email?
|
176
134
|
!external? && (
|
177
135
|
!(sorcery_config.activation_needed_email_method_name.nil? ||
|
@@ -3,22 +3,22 @@ require 'securerandom'
|
|
3
3
|
module Sorcery
|
4
4
|
module Model
|
5
5
|
# This module encapsulates the logic for temporary token.
|
6
|
-
# A temporary token is created to identify a user in scenarios
|
6
|
+
# A temporary token is created to identify a user in scenarios
|
7
7
|
# such as reseting password and activating the user by email.
|
8
8
|
module TemporaryToken
|
9
9
|
def self.included(base)
|
10
10
|
base.extend(ClassMethods)
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
# Random code, used for salt and temporary tokens.
|
14
14
|
def self.generate_random_token
|
15
15
|
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
module ClassMethods
|
19
19
|
def load_from_token(token, token_attr_name, token_expiration_date_attr)
|
20
20
|
return nil if token.blank?
|
21
|
-
user =
|
21
|
+
user = sorcery_adapter.find_by_token(token_attr_name,token)
|
22
22
|
if !user.blank? && !user.send(token_expiration_date_attr).nil?
|
23
23
|
return Time.now.in_time_zone < user.send(token_expiration_date_attr) ? user : nil
|
24
24
|
end
|
@@ -13,6 +13,17 @@ module Sorcery
|
|
13
13
|
@user_info_mapping = {}
|
14
14
|
end
|
15
15
|
|
16
|
+
def auth_hash(access_token, hash={})
|
17
|
+
return hash if access_token.nil?
|
18
|
+
|
19
|
+
token_hash = hash.dup
|
20
|
+
token_hash[:token] = access_token.token if access_token.respond_to?(:token)
|
21
|
+
token_hash[:refresh_token] = access_token.refresh_token if access_token.respond_to?(:refresh_token)
|
22
|
+
token_hash[:expires_at] = access_token.expires_at if access_token.respond_to?(:expires_at)
|
23
|
+
token_hash[:expires_in] = access_token.expires_at if access_token.respond_to?(:expires_in)
|
24
|
+
token_hash
|
25
|
+
end
|
26
|
+
|
16
27
|
def self.name
|
17
28
|
super.gsub(/Sorcery::Providers::/, '').downcase
|
18
29
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Sorcery
|
2
|
+
module Providers
|
3
|
+
|
4
|
+
# This class adds support for OAuth with heroku.com.
|
5
|
+
|
6
|
+
# config.heroku.key = <key>
|
7
|
+
# config.heroku.secret = <secret>
|
8
|
+
# config.heroku.callback_url = "<host>/oauth/callback?provider=heroku"
|
9
|
+
# config.heroku.scope = "read"
|
10
|
+
# config.heroku.user_info_mapping = {:email => "email", :name => "email" }
|
11
|
+
|
12
|
+
# NOTE:
|
13
|
+
# The full path must be set for OAuth Callback URL when configuring the API Client Information on Heroku.
|
14
|
+
|
15
|
+
class Heroku < Base
|
16
|
+
|
17
|
+
include Protocols::Oauth2
|
18
|
+
|
19
|
+
attr_accessor :auth_path, :scope, :token_url, :user_info_path
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super
|
23
|
+
|
24
|
+
@scope = nil
|
25
|
+
@site = 'https://id.heroku.com'
|
26
|
+
@user_info_path = 'https://api.heroku.com/account'
|
27
|
+
@auth_path = '/oauth/authorize'
|
28
|
+
@token_url = '/oauth/token'
|
29
|
+
@user_info_path = '/account'
|
30
|
+
@state = SecureRandom.hex(16)
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_user_hash(access_token)
|
34
|
+
response = access_token.get(user_info_path)
|
35
|
+
body = JSON.parse(response.body)
|
36
|
+
auth_hash(access_token).tap do |h|
|
37
|
+
h[:user_info] = body
|
38
|
+
h[:uid] = body['id'].to_s
|
39
|
+
h[:email] = body['email'].to_s
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def login_url(params, session)
|
44
|
+
authorize_url({ authorize_url: auth_path })
|
45
|
+
end
|
46
|
+
|
47
|
+
# tries to login the user from access token
|
48
|
+
def process_callback(params, session)
|
49
|
+
raise "Invalid state. Potential Cross Site Forgery" if params[:state] != state
|
50
|
+
args = { }.tap do |a|
|
51
|
+
a[:code] = params[:code] if params[:code]
|
52
|
+
end
|
53
|
+
get_access_token(args, token_url: token_url, token_method: :post)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Sorcery
|
2
|
+
module Providers
|
3
|
+
# This class adds support for OAuth with Jira
|
4
|
+
#
|
5
|
+
# config.jira.key = <key>
|
6
|
+
# config.jira.secret = <secret>
|
7
|
+
# ...
|
8
|
+
#
|
9
|
+
class Jira < Base
|
10
|
+
|
11
|
+
include Protocols::Oauth
|
12
|
+
|
13
|
+
attr_accessor :access_token_path, :authorize_path, :request_token_path,
|
14
|
+
:user_info_path, :site, :signature_method, :private_key_file, :callback_url
|
15
|
+
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@configuration = {
|
19
|
+
authorize_path: '/authorize',
|
20
|
+
request_token_path: '/request-token',
|
21
|
+
access_token_path: '/access-token'
|
22
|
+
}
|
23
|
+
@user_info_path = '/users/me'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Override included get_consumer method to provide authorize_path
|
27
|
+
#read extra configurations
|
28
|
+
def get_consumer
|
29
|
+
@configuration = @configuration.merge({
|
30
|
+
site: site,
|
31
|
+
signature_method: signature_method,
|
32
|
+
consumer_key: key,
|
33
|
+
private_key_file: private_key_file
|
34
|
+
})
|
35
|
+
::OAuth::Consumer.new(@key, @secret, @configuration)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_user_hash(access_token)
|
39
|
+
response = access_token.get(user_info_path)
|
40
|
+
|
41
|
+
auth_hash(access_token).tap do |h|
|
42
|
+
h[:user_info] = JSON.parse(response.body)['users'].first
|
43
|
+
h[:uid] = user_hash[:user_info]['id'].to_s
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# calculates and returns the url to which the user should be redirected,
|
48
|
+
# to get authenticated at the external provider's site.
|
49
|
+
def login_url(params, session)
|
50
|
+
req_token = get_request_token
|
51
|
+
session[:request_token] = req_token.token
|
52
|
+
session[:request_token_secret] = req_token.secret
|
53
|
+
|
54
|
+
#it was like that -> redirect_to authorize_url({ request_token: req_token.token, request_token_secret: req_token.secret })
|
55
|
+
#for some reason Jira does not need these parameters
|
56
|
+
|
57
|
+
get_request_token(
|
58
|
+
session[:request_token],
|
59
|
+
session[:request_token_secret]
|
60
|
+
).authorize_url
|
61
|
+
end
|
62
|
+
|
63
|
+
# tries to login the user from access token
|
64
|
+
def process_callback(params, session)
|
65
|
+
args = {
|
66
|
+
oauth_verifier: params[:oauth_verifier],
|
67
|
+
request_token: session[:request_token],
|
68
|
+
request_token_secret: session[:request_token_secret]
|
69
|
+
}
|
70
|
+
|
71
|
+
args.merge!({ code: params[:code] }) if params[:code]
|
72
|
+
get_access_token(args)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -34,7 +34,7 @@ module Sorcery
|
|
34
34
|
fields = self.user_info_fields.join(',')
|
35
35
|
response = access_token.get("#{@user_info_path}:(#{fields})", 'x-li-format' => 'json')
|
36
36
|
|
37
|
-
|
37
|
+
auth_hash(access_token).tap do |h|
|
38
38
|
h[:user_info] = JSON.parse(response.body)
|
39
39
|
h[:uid] = h[:user_info]['id'].to_s
|
40
40
|
end
|