sorcery 0.7.12 → 0.7.13

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.

Files changed (35) hide show
  1. data/Gemfile +5 -4
  2. data/Gemfile.lock +8 -7
  3. data/README.rdoc +5 -1
  4. data/VERSION +1 -1
  5. data/lib/generators/sorcery/templates/initializer.rb +5 -13
  6. data/lib/sorcery/controller.rb +6 -3
  7. data/lib/sorcery/controller/submodules/brute_force_protection.rb +1 -2
  8. data/lib/sorcery/controller/submodules/external.rb +80 -14
  9. data/lib/sorcery/crypto_providers/bcrypt.rb +1 -0
  10. data/lib/sorcery/model/adapters/active_record.rb +9 -4
  11. data/lib/sorcery/model/adapters/mongo_mapper.rb +16 -14
  12. data/lib/sorcery/model/adapters/mongoid.rb +10 -4
  13. data/lib/sorcery/model/submodules/brute_force_protection.rb +8 -8
  14. data/lib/sorcery/model/submodules/remember_me.rb +4 -6
  15. data/lib/sorcery/model/submodules/reset_password.rb +4 -4
  16. data/lib/sorcery/railties/tasks.rake +2 -0
  17. data/sorcery.gemspec +9 -6
  18. data/spec/Gemfile +1 -1
  19. data/spec/Gemfile.lock +7 -10
  20. data/spec/rails3/Gemfile.lock +7 -9
  21. data/spec/rails3/app/controllers/application_controller.rb +14 -0
  22. data/spec/rails3/spec/controller_activity_logging_spec.rb +3 -0
  23. data/spec/rails3/spec/controller_oauth2_spec.rb +125 -21
  24. data/spec/rails3/spec/controller_oauth_spec.rb +102 -6
  25. data/spec/rails3/spec/controller_spec.rb +7 -0
  26. data/spec/rails3_mongo_mapper/Gemfile.lock +7 -10
  27. data/spec/rails3_mongo_mapper/app/controllers/application_controller.rb +14 -0
  28. data/spec/rails3_mongo_mapper/spec/controller_spec.rb +7 -0
  29. data/spec/rails3_mongoid/Gemfile.lock +7 -10
  30. data/spec/rails3_mongoid/app/controllers/application_controller.rb +14 -0
  31. data/spec/rails3_mongoid/spec/controller_spec.rb +7 -0
  32. data/spec/shared_examples/controller_oauth2_shared_examples.rb +20 -1
  33. data/spec/shared_examples/controller_oauth_shared_examples.rb +18 -0
  34. data/spec/sorcery_crypto_providers_spec.rb +9 -0
  35. metadata +139 -123
data/Gemfile CHANGED
@@ -3,12 +3,13 @@ source :rubygems
3
3
  # Example:
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
  gem 'oauth', "~> 0.4.4"
6
- gem 'oauth2', "~> 0.5.1"
6
+ gem 'oauth2', "~> 0.6.0"
7
7
  gem 'bcrypt-ruby', "~> 3.0.0"
8
8
 
9
9
  # Add dependencies to develop your gem here.
10
10
  # Include everything needed to run rake, tests, features, etc.
11
11
  group :development do
12
+ gem 'abstract', '>= 1.0.0'
12
13
  gem "rails", ">= 3.0.0"
13
14
  gem 'json', ">= 1.5.1"
14
15
  gem "rspec", "~> 2.5.0"
@@ -20,7 +21,7 @@ group :development do
20
21
  gem "jeweler", "~> 1.8.3"
21
22
  gem 'simplecov', '>= 0.3.8', :require => false # Will install simplecov-html as a dependency
22
23
  gem 'timecop'
23
- gem 'capybara'
24
- gem 'mongo_mapper'
25
- gem 'mongoid', "~> 2.4.4"
24
+ gem 'capybara'
25
+ gem 'mongo_mapper'
26
+ gem 'mongoid', "~> 2.4.4"
26
27
  end
data/Gemfile.lock CHANGED
@@ -1,6 +1,7 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ abstract (1.0.0)
4
5
  actionmailer (3.2.2)
5
6
  actionpack (= 3.2.2)
6
7
  mail (~> 2.4.0)
@@ -28,7 +29,6 @@ GEM
28
29
  activesupport (3.2.2)
29
30
  i18n (~> 0.6)
30
31
  multi_json (~> 1.0)
31
- addressable (2.2.7)
32
32
  archive-tar-minitar (0.5.2)
33
33
  arel (3.0.2)
34
34
  bcrypt-ruby (3.0.1)
@@ -46,13 +46,12 @@ GEM
46
46
  columnize (0.3.6)
47
47
  diff-lcs (1.1.3)
48
48
  erubis (2.7.0)
49
- faraday (0.7.6)
50
- addressable (~> 2.2)
49
+ faraday (0.8.1)
51
50
  multipart-post (~> 1.1)
52
- rack (~> 1.1)
53
51
  ffi (1.0.11)
54
52
  git (1.2.5)
55
53
  hike (1.2.1)
54
+ httpauth (0.1)
56
55
  i18n (0.6.0)
57
56
  jeweler (1.8.3)
58
57
  bundler (~> 1.0)
@@ -82,9 +81,10 @@ GEM
82
81
  multipart-post (1.1.5)
83
82
  nokogiri (1.5.2)
84
83
  oauth (0.4.5)
85
- oauth2 (0.5.2)
84
+ oauth2 (0.6.1)
86
85
  faraday (~> 0.7)
87
- multi_json (~> 1.0)
86
+ httpauth (~> 0.1)
87
+ multi_json (~> 1.3)
88
88
  plucky (0.4.4)
89
89
  mongo (~> 1.5)
90
90
  polyglot (0.3.3)
@@ -168,6 +168,7 @@ PLATFORMS
168
168
  ruby
169
169
 
170
170
  DEPENDENCIES
171
+ abstract (>= 1.0.0)
171
172
  bcrypt-ruby (~> 3.0.0)
172
173
  bundler (>= 1.1.0)
173
174
  capybara
@@ -176,7 +177,7 @@ DEPENDENCIES
176
177
  mongo_mapper
177
178
  mongoid (~> 2.4.4)
178
179
  oauth (~> 0.4.4)
179
- oauth2 (~> 0.5.1)
180
+ oauth2 (~> 0.6.0)
180
181
  rails (>= 3.0.0)
181
182
  rspec (~> 2.5.0)
182
183
  rspec-rails (~> 2.5.0)
data/README.rdoc CHANGED
@@ -29,7 +29,7 @@ Railscast: http://railscasts.com/episodes/283-authentication-with-sorcery
29
29
 
30
30
  Example Rails 3 app using sorcery: https://github.com/NoamB/sorcery-example-app
31
31
 
32
- Documentation: http://rubydoc.info/gems/sorcery/0.7.12/frames
32
+ Documentation: http://rubydoc.info/gems/sorcery/0.7.13/frames
33
33
 
34
34
  Check out the tutorials in the github wiki!
35
35
 
@@ -138,6 +138,10 @@ the `config/initializers/sorcery.rb` file. After that all emails will be sent as
138
138
  end
139
139
 
140
140
 
141
+ == Single Table Inheritance (STI) Support
142
+ STI is supported via a single setting in config/initializers/sorcery.rb.
143
+
144
+
141
145
  == Full Features List by module:
142
146
 
143
147
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.12
1
+ 0.7.13
@@ -218,14 +218,14 @@ Rails.application.config.sorcery.configure do |config|
218
218
  # Default: `nil`
219
219
  #
220
220
  # user.user_activation_mailer =
221
-
222
-
221
+
222
+
223
223
  # when true sorcery will not automatically
224
224
  # email activation details and allow you to
225
225
  # manually handle how and when email is sent.
226
226
  # Default: `false`
227
227
  #
228
- # user.activation_mailer_disabled =
228
+ # user.activation_mailer_disabled =
229
229
 
230
230
 
231
231
  # activation needed email method on your mailer class.
@@ -282,17 +282,9 @@ Rails.application.config.sorcery.configure do |config|
282
282
  # manually handle how and when email is sent
283
283
  # Default: `false`
284
284
  #
285
- # user.reset_password_mailer_disabled =
285
+ # user.reset_password_mailer_disabled =
286
286
 
287
-
288
- # reset password email
289
- # method on your mailer
290
- # class.
291
- # Default: `:reset_password_email`
292
- #
293
- # user.reset_password_email_method_name =
294
287
 
295
-
296
288
  # how many seconds before the reset request expires. nil for never expires.
297
289
  # Default: `nil`
298
290
  #
@@ -347,7 +339,7 @@ Rails.application.config.sorcery.configure do |config|
347
339
 
348
340
  # Unlock token mailer class
349
341
  # Default: `nil`
350
- #
342
+ #
351
343
  # user.unlock_token_mailer = UserMailer
352
344
 
353
345
  # -- activity logging --
@@ -21,7 +21,7 @@ module Sorcery
21
21
  # If all attempts to auto-login fail, the failure callback will be called.
22
22
  def require_login
23
23
  if !logged_in?
24
- session[:return_to_url] = request.url if Config.save_return_to_url
24
+ session[:return_to_url] = request.url if Config.save_return_to_url && request.get?
25
25
  self.send(Config.not_authenticated_action)
26
26
  end
27
27
  end
@@ -110,10 +110,13 @@ module Sorcery
110
110
  end
111
111
 
112
112
  def login_from_session
113
- @current_user = (user_class.find_by_id(session[:user_id]) if session[:user_id]) || false
113
+ @current_user = (user_class.find(session[:user_id]) if session[:user_id]) || false
114
+ rescue => exception
115
+ return false if defined?(Mongoid) and exception.is_a?(Mongoid::Errors::DocumentNotFound)
116
+ raise exception
114
117
  end
115
118
 
116
- def after_login!(user, credentials)
119
+ def after_login!(user, credentials = [])
117
120
  Config.after_login.each {|c| self.send(c, user, credentials)}
118
121
  end
119
122
 
@@ -29,8 +29,7 @@ module Sorcery
29
29
  # Resets the failed logins counter.
30
30
  # Runs as a hook after a successful login.
31
31
  def reset_failed_logins_count!(user, credentials)
32
- user.send(:"#{user_class.sorcery_config.failed_logins_count_attribute_name}=", 0)
33
- user.save!(:validate => false)
32
+ user.update_many_attributes(user_class.sorcery_config.failed_logins_count_attribute_name => 0)
34
33
  end
35
34
  end
36
35
  end
@@ -10,12 +10,12 @@ module Sorcery
10
10
  class << self
11
11
  attr_reader :external_providers # external providers like twitter.
12
12
  attr_accessor :ca_file # path to ca_file. By default use a internal ca-bundle.crt.
13
-
13
+
14
14
  def merge_external_defaults!
15
15
  @defaults.merge!(:@external_providers => [],
16
16
  :@ca_file => File.join(File.expand_path(File.dirname(__FILE__)), 'external/protocols/certs/ca-bundle.crt'))
17
17
  end
18
-
18
+
19
19
  def external_providers=(providers)
20
20
  providers.each do |provider|
21
21
  include Providers.const_get(provider.to_s.split("_").map {|p| p.capitalize}.join(""))
@@ -28,18 +28,26 @@ module Sorcery
28
28
 
29
29
  module InstanceMethods
30
30
  protected
31
-
31
+
32
32
  # sends user to authenticate at the provider's website.
33
33
  # after authentication the user is redirected to the callback defined in the provider config
34
34
  def login_at(provider, args = {})
35
35
  @provider = Config.send(provider)
36
+ if @provider.callback_url.present? && @provider.callback_url[0] == '/'
37
+ uri = URI.parse(request.url.gsub(/\?.*$/,''))
38
+ uri.path = ''
39
+ uri.query = nil
40
+ uri.scheme = 'https' if(request.env['HTTP_X_FORWARDED_PROTO'] == 'https')
41
+ host = uri.to_s
42
+ @provider.callback_url = "#{host}#{@provider.callback_url}"
43
+ end
36
44
  if @provider.has_callback?
37
45
  redirect_to @provider.login_url(params,session)
38
46
  else
39
47
  #@provider.login(args)
40
48
  end
41
49
  end
42
-
50
+
43
51
  # tries to login the user from provider's callback
44
52
  def login_from(provider)
45
53
  @provider = Config.send(provider)
@@ -50,6 +58,7 @@ module Sorcery
50
58
  reset_session
51
59
  session[:return_to_url] = return_to_url
52
60
  auto_login(user)
61
+ after_login!(user)
53
62
  user
54
63
  end
55
64
  end
@@ -59,7 +68,48 @@ module Sorcery
59
68
  @provider = Config.send(provider)
60
69
  @provider.access_token
61
70
  end
62
-
71
+
72
+ # If user is logged, he can add all available providers into his account
73
+ def add_provider_to_user(provider)
74
+ provider_name = provider.to_sym
75
+ @provider = Config.send(provider_name)
76
+ @provider.process_callback(params,session)
77
+ @user_hash = @provider.get_user_hash
78
+ config = user_class.sorcery_config
79
+
80
+ # first check to see if user has a particular authentication already
81
+ unless (current_user.send(config.authentications_class.to_s.downcase.pluralize).send("find_by_#{config.provider_attribute_name}_and_#{config.provider_uid_attribute_name}", provider, @user_hash[:uid]))
82
+ user = current_user.send(config.authentications_class.to_s.downcase.pluralize).build(config.provider_uid_attribute_name => @user_hash[:uid], config.provider_attribute_name => provider_name.to_s)
83
+ user.save(:validate => false)
84
+ else
85
+ user = false
86
+ end
87
+
88
+ return user
89
+ end
90
+
91
+ # Initialize new user from provider informations.
92
+ # If a provider doesn't give required informations or username/email is already taken,
93
+ # we store provider/user infos into a session and can be rendered into registration form
94
+ def create_and_validate_from(provider)
95
+ provider = provider.to_sym
96
+ @provider = Config.send(provider)
97
+ @user_hash = @provider.get_user_hash
98
+ config = user_class.sorcery_config
99
+
100
+ attrs = user_attrs(@provider.user_info_mapping, @user_hash)
101
+
102
+ user = user_class.new(attrs)
103
+ user.send(config.authentications_class.to_s.downcase.pluralize).build(config.provider_uid_attribute_name => @user_hash[:uid], config.provider_attribute_name => provider)
104
+
105
+ session[:incomplete_user] = {
106
+ :provider => {config.provider_uid_attribute_name => @user_hash[:uid], config.provider_attribute_name => provider},
107
+ :user_hash => attrs
108
+ } unless user.save
109
+
110
+ return user
111
+ end
112
+
63
113
  # this method automatically creates a new user from the data in the external user hash.
64
114
  # The mappings from user hash fields to user db fields are set at controller config.
65
115
  # If the hash field you would like to map is nested, use slashes. For example, Given a hash like:
@@ -72,30 +122,46 @@ module Sorcery
72
122
  #
73
123
  # And this will cause 'moishe' to be set as the value of :username field.
74
124
  # Note: Be careful. This method skips validations model.
125
+ # Instead you can pass a block, if the block returns false the user will not be created
126
+ #
127
+ # create_from(provider) {|user| user.some_check }
128
+ #
75
129
  def create_from(provider)
76
130
  provider = provider.to_sym
77
131
  @provider = Config.send(provider)
78
132
  @user_hash = @provider.get_user_hash
79
133
  config = user_class.sorcery_config
80
- attrs = {}
81
- @provider.user_info_mapping.each do |k,v|
82
- if (varr = v.split("/")).size > 1
83
- attribute_value = varr.inject(@user_hash[:user_info]) {|hsh,v| hsh[v] } rescue nil
84
- attribute_value.nil? ? attrs : attrs.merge!(k => attribute_value)
85
- else
86
- attrs.merge!(k => @user_hash[:user_info][v])
87
- end
88
- end
134
+
135
+ attrs = user_attrs(@provider.user_info_mapping, @user_hash)
136
+
89
137
  user_class.transaction do
90
138
  @user = user_class.new()
91
139
  attrs.each do |k,v|
92
140
  @user.send(:"#{k}=", v)
93
141
  end
142
+
143
+ if block_given?
144
+ return false unless yield @user
145
+ end
146
+
94
147
  @user.save(:validate => false)
95
148
  user_class.sorcery_config.authentications_class.create!({config.authentications_user_id_attribute_name => @user.id, config.provider_attribute_name => provider, config.provider_uid_attribute_name => @user_hash[:uid]})
96
149
  end
97
150
  @user
98
151
  end
152
+
153
+ def user_attrs(user_info_mapping, user_hash)
154
+ attrs = {}
155
+ user_info_mapping.each do |k,v|
156
+ if (varr = v.split("/")).size > 1
157
+ attribute_value = varr.inject(user_hash[:user_info]) {|hash, value| hash[value]} rescue nil
158
+ attribute_value.nil? ? attrs : attrs.merge!(k => attribute_value)
159
+ else
160
+ attrs.merge!(k => user_hash[:user_info][v])
161
+ end
162
+ end
163
+ return attrs
164
+ end
99
165
  end
100
166
  end
101
167
  end
@@ -48,6 +48,7 @@ module Sorcery
48
48
  @cost ||= 10
49
49
  end
50
50
  attr_writer :cost
51
+ alias :stretches :cost
51
52
  alias :stretches= :cost=
52
53
 
53
54
  # Creates a BCrypt hash for the password passed.
@@ -8,11 +8,16 @@ module Sorcery
8
8
  end
9
9
 
10
10
  module InstanceMethods
11
- def update_single_attribute(name, value)
12
- self.send(:"#{name}=", value)
13
-
11
+ def update_many_attributes(attrs)
12
+ attrs.each do |name, value|
13
+ self.send(:"#{name}=", value)
14
+ end
14
15
  primary_key = self.class.primary_key
15
- self.class.where(:"#{primary_key}" => self.send(:"#{primary_key}")).update_all(name => value)
16
+ self.class.where(:"#{primary_key}" => self.send(:"#{primary_key}")).update_all(attrs)
17
+ end
18
+
19
+ def update_single_attribute(name, value)
20
+ update_many_attributes(name => value)
16
21
  end
17
22
  end
18
23
 
@@ -3,19 +3,21 @@ module Sorcery
3
3
  module Adapters
4
4
  module MongoMapper
5
5
  extend ActiveSupport::Concern
6
-
6
+
7
7
  included do
8
8
  include Sorcery::Model
9
9
  end
10
-
11
- module InstanceMethods
12
- def increment(attr)
13
- self.class.increment(id, attr => 1)
14
- end
15
-
16
- def save!(options = {})
17
- save(options)
18
- end
10
+
11
+ def increment(attr)
12
+ self.class.increment(id, attr => 1)
13
+ end
14
+
15
+ def save!(options = {})
16
+ save(options)
17
+ end
18
+
19
+ def update_many_attributes(attrs)
20
+ update_attributes(attrs)
19
21
  end
20
22
 
21
23
  module ClassMethods
@@ -31,19 +33,19 @@ module Sorcery
31
33
  end
32
34
  @user
33
35
  end
34
-
36
+
35
37
  def find_by_id(id)
36
38
  find(id)
37
39
  end
38
-
40
+
39
41
  def find_by_activation_token(token)
40
42
  where(sorcery_config.activation_token_attribute_name => token).first
41
43
  end
42
-
44
+
43
45
  def transaction(&blk)
44
46
  tap(&blk)
45
47
  end
46
-
48
+
47
49
  def find_by_sorcery_token(token_attr_name, token)
48
50
  where(token_attr_name => token).first
49
51
  end
@@ -11,11 +11,17 @@ module Sorcery
11
11
  def increment(attr)
12
12
  self.inc(attr,1)
13
13
  end
14
-
14
+
15
+ def update_many_attributes(attrs)
16
+ attrs.each do |name, value|
17
+ attrs[name] = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
18
+ self.send(:"#{name}=", value)
19
+ end
20
+ self.class.where(:_id => self.id).update_all(attrs)
21
+ end
22
+
15
23
  def update_single_attribute(name, value)
16
- value = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
17
- self.send(:"#{name}=", value)
18
- self.class.where(:_id => self.id).update_all(name => value)
24
+ update_many_attributes(name => value)
19
25
  end
20
26
  end
21
27