sorcery 0.8.5 → 0.9.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.
Files changed (163) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.travis.yml +122 -5
  4. data/CHANGELOG.md +37 -1
  5. data/Gemfile +10 -18
  6. data/README.md +159 -88
  7. data/gemfiles/active_record-rails40.gemfile +7 -0
  8. data/gemfiles/active_record-rails41.gemfile +7 -0
  9. data/gemfiles/mongo_mapper-rails40.gemfile +9 -0
  10. data/gemfiles/mongo_mapper-rails41.gemfile +9 -0
  11. data/gemfiles/mongoid-rails40.gemfile +9 -0
  12. data/gemfiles/mongoid-rails41.gemfile +9 -0
  13. data/gemfiles/mongoid3-rails32.gemfile +9 -0
  14. data/lib/generators/sorcery/USAGE +1 -1
  15. data/lib/generators/sorcery/install_generator.rb +19 -5
  16. data/lib/generators/sorcery/templates/initializer.rb +34 -9
  17. data/lib/generators/sorcery/templates/migration/brute_force_protection.rb +3 -1
  18. data/lib/generators/sorcery/templates/migration/core.rb +2 -2
  19. data/lib/generators/sorcery/templates/migration/external.rb +3 -1
  20. data/lib/sorcery/adapters/active_record_adapter.rb +120 -0
  21. data/lib/sorcery/adapters/base_adapter.rb +30 -0
  22. data/lib/sorcery/adapters/data_mapper_adapter.rb +176 -0
  23. data/lib/sorcery/adapters/mongo_mapper_adapter.rb +110 -0
  24. data/lib/sorcery/adapters/mongoid_adapter.rb +97 -0
  25. data/lib/sorcery/controller/config.rb +65 -0
  26. data/lib/sorcery/controller/submodules/activity_logging.rb +16 -21
  27. data/lib/sorcery/controller/submodules/brute_force_protection.rb +6 -6
  28. data/lib/sorcery/controller/submodules/external.rb +35 -40
  29. data/lib/sorcery/controller/submodules/remember_me.rb +4 -4
  30. data/lib/sorcery/controller/submodules/session_timeout.rb +10 -6
  31. data/lib/sorcery/controller.rb +10 -74
  32. data/lib/sorcery/model/config.rb +96 -0
  33. data/lib/sorcery/model/submodules/activity_logging.rb +30 -13
  34. data/lib/sorcery/model/submodules/brute_force_protection.rb +21 -21
  35. data/lib/sorcery/model/submodules/external.rb +53 -9
  36. data/lib/sorcery/model/submodules/remember_me.rb +15 -19
  37. data/lib/sorcery/model/submodules/reset_password.rb +33 -34
  38. data/lib/sorcery/model/submodules/user_activation.rb +36 -47
  39. data/lib/sorcery/model/temporary_token.rb +4 -4
  40. data/lib/sorcery/model.rb +73 -173
  41. data/lib/sorcery/protocols/oauth.rb +42 -0
  42. data/lib/sorcery/protocols/oauth2.rb +47 -0
  43. data/lib/sorcery/providers/base.rb +38 -0
  44. data/lib/sorcery/providers/facebook.rb +63 -0
  45. data/lib/sorcery/providers/github.rb +51 -0
  46. data/lib/sorcery/providers/google.rb +51 -0
  47. data/lib/sorcery/providers/heroku.rb +57 -0
  48. data/lib/sorcery/providers/jira.rb +77 -0
  49. data/lib/sorcery/providers/linkedin.rb +66 -0
  50. data/lib/sorcery/providers/liveid.rb +53 -0
  51. data/lib/sorcery/providers/salesforce.rb +50 -0
  52. data/lib/sorcery/providers/twitter.rb +59 -0
  53. data/lib/sorcery/providers/vk.rb +63 -0
  54. data/lib/sorcery/providers/xing.rb +64 -0
  55. data/lib/sorcery/test_helpers/internal/rails.rb +14 -3
  56. data/lib/sorcery/test_helpers/internal.rb +7 -3
  57. data/lib/sorcery/test_helpers/rails/controller.rb +21 -0
  58. data/lib/sorcery/test_helpers/rails/integration.rb +26 -0
  59. data/lib/sorcery/version.rb +3 -0
  60. data/lib/sorcery.rb +82 -58
  61. data/sorcery.gemspec +19 -19
  62. data/spec/active_record/user_activation_spec.rb +1 -1
  63. data/spec/active_record/user_activity_logging_spec.rb +10 -1
  64. data/spec/active_record/user_brute_force_protection_spec.rb +1 -1
  65. data/spec/active_record/user_oauth_spec.rb +1 -1
  66. data/spec/active_record/user_remember_me_spec.rb +1 -1
  67. data/spec/active_record/user_reset_password_spec.rb +1 -1
  68. data/spec/active_record/user_spec.rb +7 -8
  69. data/spec/controllers/controller_activity_logging_spec.rb +124 -0
  70. data/spec/controllers/controller_brute_force_protection_spec.rb +43 -0
  71. data/spec/controllers/controller_http_basic_auth_spec.rb +68 -0
  72. data/spec/controllers/controller_oauth2_spec.rb +414 -0
  73. data/spec/controllers/controller_oauth_spec.rb +240 -0
  74. data/spec/controllers/controller_remember_me_spec.rb +117 -0
  75. data/spec/controllers/controller_session_timeout_spec.rb +80 -0
  76. data/spec/controllers/controller_spec.rb +218 -0
  77. data/spec/data_mapper/user_activation_spec.rb +10 -0
  78. data/spec/data_mapper/user_activity_logging_spec.rb +14 -0
  79. data/spec/data_mapper/user_brute_force_protection_spec.rb +9 -0
  80. data/spec/data_mapper/user_oauth_spec.rb +9 -0
  81. data/spec/data_mapper/user_remember_me_spec.rb +8 -0
  82. data/spec/data_mapper/user_reset_password_spec.rb +8 -0
  83. data/spec/data_mapper/user_spec.rb +27 -0
  84. data/spec/mongo_mapper/user_activation_spec.rb +1 -2
  85. data/spec/mongo_mapper/user_activity_logging_spec.rb +1 -1
  86. data/spec/mongo_mapper/user_brute_force_protection_spec.rb +1 -1
  87. data/spec/mongo_mapper/user_oauth_spec.rb +1 -1
  88. data/spec/mongo_mapper/user_remember_me_spec.rb +1 -1
  89. data/spec/mongo_mapper/user_reset_password_spec.rb +1 -1
  90. data/spec/mongo_mapper/user_spec.rb +7 -8
  91. data/spec/mongoid/user_activation_spec.rb +1 -2
  92. data/spec/mongoid/user_activity_logging_spec.rb +1 -2
  93. data/spec/mongoid/user_brute_force_protection_spec.rb +1 -2
  94. data/spec/mongoid/user_oauth_spec.rb +1 -2
  95. data/spec/mongoid/user_remember_me_spec.rb +1 -2
  96. data/spec/mongoid/user_reset_password_spec.rb +1 -2
  97. data/spec/mongoid/user_spec.rb +21 -9
  98. data/spec/orm/active_record.rb +14 -0
  99. data/spec/orm/data_mapper.rb +48 -0
  100. data/spec/orm/mongo_mapper.rb +1 -1
  101. data/spec/orm/mongoid.rb +5 -0
  102. data/spec/rails_app/app/controllers/sorcery_controller.rb +125 -59
  103. data/spec/rails_app/app/data_mapper/authentication.rb +8 -0
  104. data/spec/rails_app/app/data_mapper/user.rb +7 -0
  105. data/spec/rails_app/app/mongo_mapper/user.rb +2 -0
  106. data/spec/rails_app/config/routes.rb +27 -13
  107. data/spec/rails_app/db/migrate/core/20101224223620_create_users.rb +2 -2
  108. data/spec/shared_examples/user_activation_shared_examples.rb +108 -91
  109. data/spec/shared_examples/user_activity_logging_shared_examples.rb +83 -15
  110. data/spec/shared_examples/user_brute_force_protection_shared_examples.rb +140 -21
  111. data/spec/shared_examples/user_oauth_shared_examples.rb +21 -16
  112. data/spec/shared_examples/user_remember_me_shared_examples.rb +36 -24
  113. data/spec/shared_examples/user_reset_password_shared_examples.rb +138 -117
  114. data/spec/shared_examples/user_shared_examples.rb +297 -150
  115. data/spec/sorcery_crypto_providers_spec.rb +28 -28
  116. data/spec/spec_helper.rb +12 -18
  117. metadata +99 -165
  118. data/Gemfile.rails4 +0 -24
  119. data/VERSION +0 -1
  120. data/lib/sorcery/controller/submodules/external/protocols/oauth1.rb +0 -46
  121. data/lib/sorcery/controller/submodules/external/protocols/oauth2.rb +0 -50
  122. data/lib/sorcery/controller/submodules/external/providers/base.rb +0 -21
  123. data/lib/sorcery/controller/submodules/external/providers/facebook.rb +0 -99
  124. data/lib/sorcery/controller/submodules/external/providers/github.rb +0 -93
  125. data/lib/sorcery/controller/submodules/external/providers/google.rb +0 -92
  126. data/lib/sorcery/controller/submodules/external/providers/linkedin.rb +0 -103
  127. data/lib/sorcery/controller/submodules/external/providers/liveid.rb +0 -93
  128. data/lib/sorcery/controller/submodules/external/providers/twitter.rb +0 -94
  129. data/lib/sorcery/controller/submodules/external/providers/vk.rb +0 -101
  130. data/lib/sorcery/controller/submodules/external/providers/xing.rb +0 -98
  131. data/lib/sorcery/model/adapters/active_record.rb +0 -49
  132. data/lib/sorcery/model/adapters/mongo_mapper.rb +0 -56
  133. data/lib/sorcery/model/adapters/mongoid.rb +0 -88
  134. data/lib/sorcery/test_helpers/rails.rb +0 -16
  135. data/lib/sorcery/test_helpers.rb +0 -5
  136. data/spec/active_record/controller_activity_logging_spec.rb +0 -140
  137. data/spec/active_record/controller_brute_force_protection_spec.rb +0 -136
  138. data/spec/active_record/controller_http_basic_auth_spec.rb +0 -59
  139. data/spec/active_record/controller_oauth2_spec.rb +0 -417
  140. data/spec/active_record/controller_oauth_spec.rb +0 -212
  141. data/spec/active_record/controller_remember_me_spec.rb +0 -96
  142. data/spec/active_record/controller_session_timeout_spec.rb +0 -55
  143. data/spec/active_record/controller_spec.rb +0 -182
  144. data/spec/active_record/integration_spec.rb +0 -23
  145. data/spec/mongo_mapper/controller_spec.rb +0 -175
  146. data/spec/mongoid/controller_activity_logging_spec.rb +0 -111
  147. data/spec/mongoid/controller_spec.rb +0 -186
  148. data/spec/rails_app/public/404.html +0 -26
  149. data/spec/rails_app/public/422.html +0 -26
  150. data/spec/rails_app/public/500.html +0 -26
  151. data/spec/rails_app/public/favicon.ico +0 -0
  152. data/spec/rails_app/public/images/rails.png +0 -0
  153. data/spec/rails_app/public/javascripts/application.js +0 -2
  154. data/spec/rails_app/public/javascripts/controls.js +0 -965
  155. data/spec/rails_app/public/javascripts/dragdrop.js +0 -974
  156. data/spec/rails_app/public/javascripts/effects.js +0 -1123
  157. data/spec/rails_app/public/javascripts/prototype.js +0 -6001
  158. data/spec/rails_app/public/javascripts/rails.js +0 -175
  159. data/spec/rails_app/public/robots.txt +0 -5
  160. data/spec/rails_app/public/stylesheets/.gitkeep +0 -0
  161. data/spec/shared_examples/controller_oauth2_shared_examples.rb +0 -56
  162. data/spec/shared_examples/controller_oauth_shared_examples.rb +0 -69
  163. /data/lib/sorcery/{controller/submodules/external/protocols → protocols}/certs/ca-bundle.crt +0 -0
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 4.0.0'
4
+
5
+ gem 'mongoid', '~> 4.0.0'
6
+ gem 'sqlite3', platform: :mri
7
+ gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
8
+
9
+ gemspec path: '..'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 4.1.0'
4
+
5
+ gem 'mongoid', '~> 4.0.0'
6
+ gem 'sqlite3', platform: :mri
7
+ gem 'activerecord-jdbcsqlite3-adapter', platform: :jruby
8
+
9
+ gemspec path: '..'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rails', '~> 3.2.0'
4
+
5
+ gem 'mongoid', '~> 3.0'
6
+ gem 'bson_ext'
7
+ gem 'sqlite3'
8
+
9
+ gemspec path: '..'
@@ -16,7 +16,7 @@ Examples:
16
16
  This will generate the core migration file, the initializer and change the model class
17
17
  (in the initializer and migration files) to the class 'Person' (and it's pluralized version, 'people')
18
18
 
19
- rails generate sorcery:install http_basic_auth external remember_me --migrations
19
+ rails generate sorcery:install http_basic_auth external remember_me --only-submodules
20
20
 
21
21
  This will generate only the migration files for the specified submodules and will
22
22
  add them to the initializer file.
@@ -15,12 +15,21 @@ module Sorcery
15
15
  :desc => "Specify the model class name if you will use anything other than 'User'"
16
16
 
17
17
  class_option :migrations, :optional => true, :type => :boolean, :banner => "migrations",
18
+ :desc => "[DEPRECATED] Please use --only-submodules option instead"
19
+
20
+ class_option :only_submodules, :optional => true, :type => :boolean, :banner => "only-submodules",
18
21
  :desc => "Specify if you want to add submodules to an existing model\n\t\t\t # (will generate migrations files, and add submodules to config file)"
19
22
 
20
23
 
24
+ def check_deprecated_options
25
+ if options[:migrations]
26
+ warn("[DEPRECATED] `--migrations` option is deprecated, please use `--only-submodules` instead")
27
+ end
28
+ end
29
+
21
30
  # Copy the initializer file to config/initializers folder.
22
31
  def copy_initializer_file
23
- template "initializer.rb", sorcery_config_path unless options[:migrations]
32
+ template "initializer.rb", sorcery_config_path unless only_submodules?
24
33
  end
25
34
 
26
35
  def configure_initializer_file
@@ -36,8 +45,8 @@ module Sorcery
36
45
  end
37
46
 
38
47
  def configure_model
39
- # Generate the model and add 'authenticates_with_sorcery!' unless you passed --migrations
40
- unless options[:migrations]
48
+ # Generate the model and add 'authenticates_with_sorcery!' unless you passed --only-submodules
49
+ unless only_submodules?
41
50
  generate "model #{model_class_name} --skip-migration"
42
51
 
43
52
  inject_sorcery_to_model
@@ -52,9 +61,9 @@ module Sorcery
52
61
 
53
62
  # Copy the migrations files to db/migrate folder
54
63
  def copy_migration_files
55
- # Copy core migration file in all cases except when you pass --migrations.
64
+ # Copy core migration file in all cases except when you pass --only-submodules.
56
65
  return unless defined?(Sorcery::Generators::InstallGenerator::ActiveRecord)
57
- migration_template "migration/core.rb", "db/migrate/sorcery_core.rb" unless options[:migrations]
66
+ migration_template "migration/core.rb", "db/migrate/sorcery_core.rb" unless only_submodules?
58
67
 
59
68
  if submodules
60
69
  submodules.each do |submodule|
@@ -76,6 +85,11 @@ module Sorcery
76
85
  end
77
86
  end
78
87
 
88
+ private
89
+ def only_submodules?
90
+ options[:migrations] || options[:only_submodules]
91
+ end
92
+
79
93
  end
80
94
  end
81
95
  end
@@ -27,6 +27,12 @@ Rails.application.config.sorcery.configure do |config|
27
27
  # config.cookie_domain =
28
28
 
29
29
 
30
+ # Allow the remember_me cookie to be set through AJAX
31
+ # Default: `true`
32
+ #
33
+ # config.remember_me_httponly =
34
+
35
+
30
36
  # -- session timeout --
31
37
  # How long in seconds to keep the session alive.
32
38
  # Default: `3600`
@@ -67,7 +73,7 @@ Rails.application.config.sorcery.configure do |config|
67
73
 
68
74
 
69
75
  # -- external --
70
- # What providers are supported by this app, i.e. [:twitter, :facebook, :github, :linkedin, :xing, :google, :liveid] .
76
+ # What providers are supported by this app, i.e. [:twitter, :facebook, :github, :linkedin, :xing, :google, :liveid, :salesforce] .
71
77
  # Default: `[]`
72
78
  #
73
79
  # config.external_providers =
@@ -101,7 +107,7 @@ Rails.application.config.sorcery.configure do |config|
101
107
  # config.xing.user_info_mapping = {first_name: "first_name", last_name: "last_name"}
102
108
  #
103
109
  #
104
- # Twitter wil not accept any requests nor redirect uri containing localhost,
110
+ # Twitter will not accept any requests nor redirect uri containing localhost,
105
111
  # make sure you use 0.0.0.0:3000 to access your app in development
106
112
  #
107
113
  # config.twitter.key = ""
@@ -114,6 +120,7 @@ Rails.application.config.sorcery.configure do |config|
114
120
  # config.facebook.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=facebook"
115
121
  # config.facebook.user_info_mapping = {:email => "name"}
116
122
  # config.facebook.access_permissions = ["email", "publish_stream"]
123
+ # config.facebook.display = "page"
117
124
  #
118
125
  # config.github.key = ""
119
126
  # config.github.secret = ""
@@ -139,6 +146,29 @@ Rails.application.config.sorcery.configure do |config|
139
146
  # config.liveid.callback_url = "http://mydomain.com:3000/oauth/callback?provider=liveid"
140
147
  # config.liveid.user_info_mapping = {:username => "name"}
141
148
 
149
+ # For information about JIRA API:
150
+ # https://developer.atlassian.com/display/JIRADEV/JIRA+REST+API+Example+-+OAuth+authentication
151
+ # to obtain the consumer key and the public key you can use the jira-ruby gem https://github.com/sumoheavy/jira-ruby
152
+ # or run openssl req -x509 -nodes -newkey rsa:1024 -sha1 -keyout rsakey.pem -out rsacert.pem to obtain the public key
153
+ # Make sure you have configured the application link properly
154
+
155
+ # config.jira.key = "1234567"
156
+ # config.jira.secret = "jiraTest"
157
+ # config.jira.site = "http://localhost:2990/jira/plugins/servlet/oauth"
158
+ # config.jira.signature_method = "RSA-SHA1"
159
+ # config.jira.private_key_file = "rsakey.pem"
160
+
161
+ # For information about Salesforce API:
162
+ # https://developer.salesforce.com/signup &
163
+ # https://www.salesforce.com/us/developer/docs/api_rest/
164
+ # Salesforce callback_url must be https. You can run the following to generate self-signed ssl cert
165
+ # openssl req -new -newkey rsa:2048 -sha1 -days 365 -nodes -x509 -keyout server.key -out server.crt
166
+ # Make sure you have configured the application link properly
167
+ # config.salesforce.key = '123123'
168
+ # config.salesforce.secret = 'acb123'
169
+ # config.salesforce.callback_url = "https://127.0.0.1:9292/oauth/callback?provider=salesforce"
170
+ # config.salesforce.scope = "full"
171
+ # config.salesforce.user_info_mapping = {:email => "email"}
142
172
 
143
173
  # --- user config ---
144
174
  config.user_config do |user|
@@ -217,11 +247,6 @@ Rails.application.config.sorcery.configure do |config|
217
247
 
218
248
 
219
249
  # -- remember_me --
220
- # allow the remember_me cookie to settable through AJAX
221
- # Default: `true`
222
- #
223
- # user.remember_me_httponly =
224
-
225
250
  # How long in seconds the session length will be
226
251
  # Default: `604800`
227
252
  #
@@ -330,7 +355,7 @@ Rails.application.config.sorcery.configure do |config|
330
355
  # user.reset_password_expiration_period =
331
356
 
332
357
 
333
- # hammering protection, how long to wait before allowing another email to be sent.
358
+ # hammering protection, how long in seconds to wait before allowing another email to be sent.
334
359
  # Default: `5 * 60`
335
360
  #
336
361
  # user.reset_password_time_between_emails =
@@ -400,7 +425,7 @@ Rails.application.config.sorcery.configure do |config|
400
425
  # user.last_activity_at_attribute_name =
401
426
 
402
427
 
403
- # How long since last activity is he user defined logged out?
428
+ # How long since last activity is the user defined logged out?
404
429
  # Default: `10 * 60`
405
430
  #
406
431
  # user.activity_timeout =
@@ -3,5 +3,7 @@ class SorceryBruteForceProtection < ActiveRecord::Migration
3
3
  add_column :<%= model_class_name.tableize %>, :failed_logins_count, :integer, :default => 0
4
4
  add_column :<%= model_class_name.tableize %>, :lock_expires_at, :datetime, :default => nil
5
5
  add_column :<%= model_class_name.tableize %>, :unlock_token, :string, :default => nil
6
+
7
+ add_index :<%= model_class_name.tableize %>, :unlock_token
6
8
  end
7
- end
9
+ end
@@ -2,8 +2,8 @@ class SorceryCore < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :<%= model_class_name.tableize %> do |t|
4
4
  t.string :email, :null => false
5
- t.string :crypted_password, :null => false
6
- t.string :salt, :null => false
5
+ t.string :crypted_password
6
+ t.string :salt
7
7
 
8
8
  t.timestamps
9
9
  end
@@ -6,5 +6,7 @@ class SorceryExternal < ActiveRecord::Migration
6
6
 
7
7
  t.timestamps
8
8
  end
9
+
10
+ add_index :<%= model_class_name.tableize %>, [:provider, :uid]
9
11
  end
10
- end
12
+ end
@@ -0,0 +1,120 @@
1
+ module Sorcery
2
+ module Adapters
3
+ class ActiveRecordAdapter < BaseAdapter
4
+ def update_attributes(attrs)
5
+ attrs.each do |name, value|
6
+ @model.send(:"#{name}=", value)
7
+ end
8
+ primary_key = @model.class.primary_key
9
+ @model.class.where(:"#{primary_key}" => @model.send(:"#{primary_key}")).update_all(attrs)
10
+ end
11
+
12
+ def save(options = {})
13
+ mthd = options.delete(:raise_on_failure) ? :save! : :save
14
+ @model.send(mthd, options)
15
+ end
16
+
17
+ def increment(field)
18
+ @model.increment!(field)
19
+ end
20
+
21
+ def find_authentication_by_oauth_credentials(relation_name, provider, uid)
22
+ @user_config ||= ::Sorcery::Controller::Config.user_class.to_s.constantize.sorcery_config
23
+ conditions = {
24
+ @user_config.provider_uid_attribute_name => uid,
25
+ @user_config.provider_attribute_name => provider
26
+ }
27
+
28
+ @model.public_send(relation_name).where(conditions).first
29
+ end
30
+
31
+ class << self
32
+ def define_field(name, type, options={})
33
+ # AR fields are defined through migrations, only validator here
34
+ end
35
+
36
+ def define_callback(time, event, method_name, options={})
37
+ @klass.send "#{time}_#{event}", method_name, options.slice(:if)
38
+ end
39
+
40
+ def find_by_oauth_credentials(provider, uid)
41
+ @user_config ||= ::Sorcery::Controller::Config.user_class.to_s.constantize.sorcery_config
42
+ conditions = {
43
+ @user_config.provider_uid_attribute_name => uid,
44
+ @user_config.provider_attribute_name => provider
45
+ }
46
+
47
+ @klass.where(conditions).first
48
+ end
49
+
50
+ def find_by_remember_me_token(token)
51
+ @klass.where(@klass.sorcery_config.remember_me_token_attribute_name => token).first
52
+ end
53
+
54
+ def find_by_credentials(credentials)
55
+ relation = nil
56
+
57
+ @klass.sorcery_config.username_attribute_names.each do |attribute|
58
+ if @klass.sorcery_config.downcase_username_before_authenticating
59
+ condition = @klass.arel_table[attribute].lower.eq(@klass.arel_table.lower(credentials[0]))
60
+ else
61
+ condition = @klass.arel_table[attribute].eq(credentials[0])
62
+ end
63
+
64
+ if relation.nil?
65
+ relation = condition
66
+ else
67
+ relation = relation.or(condition)
68
+ end
69
+ end
70
+
71
+ @klass.where(relation).first
72
+ end
73
+
74
+ def find_by_token(token_attr_name, token)
75
+ condition = @klass.arel_table[token_attr_name].eq(token)
76
+
77
+ @klass.where(condition).first
78
+ end
79
+
80
+ def find_by_activation_token(token)
81
+ @klass.where(@klass.sorcery_config.activation_token_attribute_name => token).first
82
+ end
83
+
84
+ def find_by_id(id)
85
+ @klass.find_by_id(id)
86
+ end
87
+
88
+ def find_by_username(username)
89
+ @klass.sorcery_config.username_attribute_names.each do |attribute|
90
+ if @klass.sorcery_config.downcase_username_before_authenticating
91
+ username = username.downcase
92
+ end
93
+
94
+ result = @klass.where(attribute => username).first
95
+ return result if result
96
+ end
97
+ end
98
+
99
+ def find_by_email(email)
100
+ @klass.where(@klass.sorcery_config.email_attribute_name => email).first
101
+ end
102
+
103
+ def get_current_users
104
+ config = @klass.sorcery_config
105
+
106
+ @klass
107
+ .where("#{config.last_activity_at_attribute_name} IS NOT NULL") \
108
+ .where("#{config.last_logout_at_attribute_name} IS NULL OR #{config.last_activity_at_attribute_name} > #{config.last_logout_at_attribute_name}") \
109
+ .where("#{config.last_activity_at_attribute_name} > ? ", config.activity_timeout.seconds.ago.utc.to_s(:db))
110
+ end
111
+
112
+ def transaction(&blk)
113
+ @klass.tap(&blk)
114
+ end
115
+ end
116
+ end
117
+
118
+
119
+ end
120
+ end
@@ -0,0 +1,30 @@
1
+ module Sorcery
2
+ module Adapters
3
+ class BaseAdapter
4
+ def initialize(model)
5
+ @model = model
6
+ end
7
+
8
+ def self.from(klass)
9
+ @klass = klass
10
+ self
11
+ end
12
+
13
+ def self.delete_all
14
+ @klass.delete_all
15
+ end
16
+
17
+ def self.find(id)
18
+ find_by_id(id)
19
+ end
20
+
21
+ def increment(field)
22
+ @model.increment(field)
23
+ end
24
+
25
+ def update_attribute(name, value)
26
+ update_attributes(name => value)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,176 @@
1
+ module Sorcery
2
+ module Adapters
3
+ class DataMapperAdapter < BaseAdapter
4
+ module Wrapper
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ sorcery_adapter.verify_submodules_compatibility!
9
+ end
10
+
11
+ def sorcery_adapter
12
+ @sorcery_adapter ||= Sorcery::Adapters::DataMapperAdapter.new(self)
13
+ end
14
+
15
+ module ClassMethods
16
+ def sorcery_adapter
17
+ Sorcery::Adapters::DataMapperAdapter.from(self)
18
+ end
19
+ end
20
+ end
21
+
22
+ def increment(attr)
23
+ @model[attr] ||= 0
24
+ @model[attr] += 1
25
+ @model
26
+ end
27
+
28
+ def update_attributes(attrs)
29
+ attrs.each do |name, value|
30
+ value = value.utc if value.is_a?(ActiveSupport::TimeWithZone)
31
+ @model.send(:"#{name}=", value)
32
+ end
33
+ @model.class.get(@model.id).update(attrs)
34
+ end
35
+
36
+ def update_attribute(name, value)
37
+ update_attributes(name => value)
38
+ end
39
+
40
+ def save(options = {})
41
+ if options.key?(:validate) && !options[:validate]
42
+ @model.save!
43
+ else
44
+ @model.save
45
+ end
46
+ end
47
+
48
+ class << self
49
+ def define_field(name, type, options={})
50
+ @klass.property name, type, options.slice(:length, :default)
51
+
52
+ # Workaround local timezone retrieval problem NOTE dm-core issue #193
53
+ if type == Time
54
+ @klass.send(:alias_method, "orig_#{name}", name)
55
+ @klass.send :define_method, name do
56
+ t = send("orig_#{name}")
57
+ t && Time.new(t.year, t.month, t.day, t.hour, t.min, t.sec, 0)
58
+ end
59
+ end
60
+ end
61
+
62
+ def define_callback(time, event, method_name, options={})
63
+ event = :valid? if event == :validation
64
+ condition = options[:if]
65
+
66
+ user_klass = @klass
67
+
68
+ block = Proc.new do |record|
69
+ if condition.nil?
70
+ send(method_name)
71
+ elsif condition.respond_to?(:call)
72
+ send(method_name) if condition.call(self)
73
+ elsif condition.is_a? Symbol
74
+ send(method_name) if send(condition)
75
+ end
76
+ end
77
+
78
+ @klass.send(time, event, &block)
79
+ end
80
+
81
+ def find(id)
82
+ @klass.get(id)
83
+ end
84
+
85
+ def delete_all
86
+ @klass.destroy
87
+ end
88
+
89
+ # NOTE
90
+ # DM Adapter dependent
91
+ # DM creates MySQL tables case insensitive by default
92
+ # http://datamapper.lighthouseapp.com/projects/20609-datamapper/tickets/1105
93
+ def find_by_credentials(credentials)
94
+ credential = credentials[0].dup
95
+ credential.downcase! if @klass.sorcery_config.downcase_username_before_authenticating
96
+ @klass.sorcery_config.username_attribute_names.each do |name|
97
+ @user = @klass.first(name => credential)
98
+ break if @user
99
+ end
100
+ !!@user ? @klass.get(@user.id) : nil
101
+ end
102
+
103
+ def find_by_oauth_credentials(provider, uid)
104
+ @user_config = ::Sorcery::Controller::Config.user_class.to_s.constantize.sorcery_config
105
+ user = @klass.first(@user_config.provider_attribute_name => provider, @user_config.provider_uid_attribute_name => uid)
106
+ !!user ? @klass.get(user.id) : nil
107
+ end
108
+
109
+ def find_by_token(token_attr_name, token)
110
+ @klass.first(token_attr_name => token)
111
+ end
112
+
113
+ def find_by_id(id)
114
+ @klass.get(id)
115
+ rescue ::DataMapper::ObjectNotFoundError
116
+ nil
117
+ end
118
+
119
+ def find_by_activation_token(token)
120
+ user = @klass.first(@klass.sorcery_config.activation_token_attribute_name => token)
121
+ !!user ? @klass.get(user.id) : nil
122
+ end
123
+
124
+ def find_by_remember_me_token(token)
125
+ user = @klass.first(@klass.sorcery_config.remember_me_token_attribute_name => token)
126
+ !!user ? @klass.get(user.id) : nil
127
+ end
128
+
129
+ def find_by_username(username)
130
+ user = nil
131
+ @klass.sorcery_config.username_attribute_names.each do |name|
132
+ user = @klass.first(name => username)
133
+ break if user
134
+ end
135
+ !!user ? @klass.get(user.id) : nil
136
+ end
137
+
138
+ def transaction(&blk)
139
+ @klass.tap(&blk)
140
+ end
141
+
142
+ def find_by_sorcery_token(token_attr_name, token)
143
+ user = @klass.first(token_attr_name => token)
144
+ !!user ? @klass.get(user.id) : nil
145
+ end
146
+
147
+ def find_by_email(email)
148
+ user = @klass.first(@klass.sorcery_config.email_attribute_name => email)
149
+ !!user ? @klass.get(user.id) : nil
150
+ end
151
+
152
+ # NOTE
153
+ # DM Adapter dependent
154
+ def get_current_users
155
+ unless @klass.repository.adapter.is_a?(::DataMapper::Adapters::MysqlAdapter)
156
+ raise 'Unsupported DataMapper Adapter'
157
+ end
158
+ config = @klass.sorcery_config
159
+ ret = @klass.all(config.last_logout_at_attribute_name => nil) |
160
+ @klass.all(config.last_activity_at_attribute_name.gt => config.last_logout_at_attribute_name)
161
+ ret = ret.all(config.last_activity_at_attribute_name.not => nil)
162
+ ret = ret.all(config.last_activity_at_attribute_name.gt => config.activity_timeout.seconds.ago.utc)
163
+ ret
164
+ end
165
+
166
+ def verify_submodules_compatibility!
167
+ active_submodules = [::Sorcery::Controller::Config.submodules].flatten
168
+
169
+ if active_submodules.include?(:activity_logging) && !repository.adapter.is_a?(::DataMapper::Adapters::MysqlAdapter)
170
+ raise "DataMapper adapter compatibility error, please check documentation"
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,110 @@
1
+ module Sorcery
2
+ module Adapters
3
+ class MongoMapperAdapter < BaseAdapter
4
+ module Wrapper
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ extend Sorcery::Model
9
+ end
10
+
11
+ def sorcery_adapter
12
+ @sorcery_adapter ||= Sorcery::Adapters::MongoMapperAdapter.new(self)
13
+ end
14
+
15
+ module ClassMethods
16
+ def sorcery_adapter
17
+ Sorcery::Adapters::MongoMapperAdapter.from(self)
18
+ end
19
+ end
20
+ end
21
+
22
+ def increment(attr)
23
+ @model[attr] ||= 0
24
+ @model[attr] += 1
25
+ @model.class.increment(@model.id, attr => 1)
26
+ end
27
+
28
+ def save(options = {})
29
+ if options.delete(:raise_on_failure) && options[:validate] != false
30
+ @model.save! options
31
+ else
32
+ @model.save options
33
+ end
34
+ end
35
+
36
+ def update_attributes(attrs)
37
+ @model.update_attributes(attrs)
38
+ end
39
+
40
+ class << self
41
+ def define_field(name, type, options={})
42
+ @klass.key name, type, options.slice(:default)
43
+ end
44
+
45
+ def define_callback(time, event, method_name, options={})
46
+ @klass.send "#{time}_#{event}", method_name, options.slice(:if)
47
+ end
48
+
49
+ def credential_regex(credential)
50
+ return { :$regex => /^#{Regexp.escape(credential)}$/i } if (@klass.sorcery_config.downcase_username_before_authenticating)
51
+ return credential
52
+ end
53
+
54
+ def find_by_credentials(credentials)
55
+ user = nil
56
+ @klass.sorcery_config.username_attribute_names.each do |attribute|
57
+ user = @klass.where(attribute => credential_regex(credentials[0])).first
58
+ break if user
59
+ end
60
+ user
61
+ end
62
+
63
+ def find_by_oauth_credentials(provider, uid)
64
+ @user_config ||= ::Sorcery::Controller::Config.user_class.to_s.constantize.sorcery_config
65
+ @klass.where(@user_config.provider_attribute_name => provider, @user_config.provider_uid_attribute_name => uid).first
66
+ end
67
+
68
+ def find_by_id(id)
69
+ @klass.find(id)
70
+ end
71
+
72
+ def find_by_username(username)
73
+ if @klass.sorcery_config.downcase_username_before_authenticating
74
+ username = username.downcase
75
+ end
76
+
77
+ @klass.sorcery_config.username_attribute_names.each do |attribute|
78
+ result = @klass.where(attribute => username).first
79
+ return result if result
80
+ end
81
+ end
82
+
83
+ def find_by_activation_token(token)
84
+ @klass.where(@klass.sorcery_config.activation_token_attribute_name => token).first
85
+ end
86
+
87
+ def find_by_email(email)
88
+ @klass.where(@klass.sorcery_config.email_attribute_name => email).first
89
+ end
90
+
91
+ def find_by_token(token_attr_name, token)
92
+ @klass.where(token_attr_name => token).first
93
+ end
94
+
95
+ def transaction(&blk)
96
+ @klass.tap(&blk)
97
+ end
98
+
99
+ def find_by_sorcery_token(token_attr_name, token)
100
+ @klass.where(token_attr_name => token).first
101
+ end
102
+
103
+ def get_current_users
104
+ raise "this method is unavailable for MongoMapper"
105
+ end
106
+
107
+ end
108
+ end
109
+ end
110
+ end