stn-simple_token_authentication 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +270 -0
  4. data/Rakefile +61 -0
  5. data/doc/README.md +18 -0
  6. data/lib/simple_token_authentication.rb +58 -0
  7. data/lib/simple_token_authentication/acts_as_token_authenticatable.rb +49 -0
  8. data/lib/simple_token_authentication/acts_as_token_authentication_handler.rb +22 -0
  9. data/lib/simple_token_authentication/adapter.rb +7 -0
  10. data/lib/simple_token_authentication/adapters/active_record_adapter.rb +14 -0
  11. data/lib/simple_token_authentication/adapters/mongoid_adapter.rb +14 -0
  12. data/lib/simple_token_authentication/adapters/rails_adapter.rb +14 -0
  13. data/lib/simple_token_authentication/adapters/rails_api_adapter.rb +18 -0
  14. data/lib/simple_token_authentication/configuration.rb +45 -0
  15. data/lib/simple_token_authentication/entities_manager.rb +10 -0
  16. data/lib/simple_token_authentication/entity.rb +64 -0
  17. data/lib/simple_token_authentication/fallback_authentication_handler.rb +11 -0
  18. data/lib/simple_token_authentication/sign_in_handler.rb +19 -0
  19. data/lib/simple_token_authentication/token_authentication_handler.rb +149 -0
  20. data/lib/simple_token_authentication/token_comparator.rb +20 -0
  21. data/lib/simple_token_authentication/token_generator.rb +9 -0
  22. data/lib/simple_token_authentication/version.rb +3 -0
  23. data/lib/tasks/simple_token_authentication_tasks.rake +4 -0
  24. data/spec/configuration/action_controller_callbacks_options_spec.rb +53 -0
  25. data/spec/configuration/fallback_to_devise_option_spec.rb +128 -0
  26. data/spec/configuration/header_names_option_spec.rb +463 -0
  27. data/spec/configuration/sign_in_token_option_spec.rb +92 -0
  28. data/spec/lib/simple_token_authentication/acts_as_token_authenticatable_spec.rb +108 -0
  29. data/spec/lib/simple_token_authentication/acts_as_token_authentication_handler_spec.rb +127 -0
  30. data/spec/lib/simple_token_authentication/adapter_spec.rb +19 -0
  31. data/spec/lib/simple_token_authentication/adapters/active_record_adapter_spec.rb +21 -0
  32. data/spec/lib/simple_token_authentication/adapters/mongoid_adapter_spec.rb +21 -0
  33. data/spec/lib/simple_token_authentication/adapters/rails_adapter_spec.rb +21 -0
  34. data/spec/lib/simple_token_authentication/adapters/rails_api_adapter_spec.rb +43 -0
  35. data/spec/lib/simple_token_authentication/configuration_spec.rb +133 -0
  36. data/spec/lib/simple_token_authentication/entities_manager_spec.rb +67 -0
  37. data/spec/lib/simple_token_authentication/entity_spec.rb +190 -0
  38. data/spec/lib/simple_token_authentication/errors_spec.rb +8 -0
  39. data/spec/lib/simple_token_authentication/fallback_authentication_handler_spec.rb +24 -0
  40. data/spec/lib/simple_token_authentication/sign_in_handler_spec.rb +43 -0
  41. data/spec/lib/simple_token_authentication/token_authentication_handler_spec.rb +351 -0
  42. data/spec/lib/simple_token_authentication/token_comparator_spec.rb +19 -0
  43. data/spec/lib/simple_token_authentication/token_generator_spec.rb +19 -0
  44. data/spec/lib/simple_token_authentication_spec.rb +181 -0
  45. data/spec/spec_helper.rb +15 -0
  46. data/spec/support/dummy_classes_helper.rb +80 -0
  47. data/spec/support/spec_for_adapter.rb +10 -0
  48. data/spec/support/spec_for_authentication_handler_interface.rb +8 -0
  49. data/spec/support/spec_for_configuration_option_interface.rb +28 -0
  50. data/spec/support/spec_for_entities_manager_interface.rb +8 -0
  51. data/spec/support/spec_for_sign_in_handler_interface.rb +8 -0
  52. data/spec/support/spec_for_token_comparator_interface.rb +8 -0
  53. data/spec/support/spec_for_token_generator_interface.rb +8 -0
  54. data/spec/support/specs_for_token_authentication_handler_interface.rb +8 -0
  55. metadata +250 -0
@@ -0,0 +1,270 @@
1
+ Simple Token Authentication
2
+ ===========================
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/simple_token_authentication.svg)](http://badge.fury.io/rb/simple_token_authentication)
5
+ [![Build Status](https://travis-ci.org/gonzalo-bulnes/simple_token_authentication.svg?branch=master)](https://travis-ci.org/gonzalo-bulnes/simple_token_authentication)
6
+ [![Code Climate](https://codeclimate.com/github/gonzalo-bulnes/simple_token_authentication.svg)](https://codeclimate.com/github/gonzalo-bulnes/simple_token_authentication)
7
+ [![Dependency Status](https://gemnasium.com/gonzalo-bulnes/simple_token_authentication.svg)](https://gemnasium.com/gonzalo-bulnes/simple_token_authentication)
8
+ [![security](https://hakiri.io/github/gonzalo-bulnes/simple_token_authentication/master.svg)](https://hakiri.io/github/gonzalo-bulnes/simple_token_authentication/master)
9
+ [![Inline docs](http://inch-ci.org/github/gonzalo-bulnes/simple_token_authentication.svg?branch=master)](http://inch-ci.org/github/gonzalo-bulnes/simple_token_authentication)
10
+
11
+ Token authentication support has been removed from [Devise][devise] for security reasons. In [this gist][original-gist], Devise's [José Valim][josevalim] explains how token authentication should be performed in order to remain safe.
12
+
13
+ This gem packages the content of the gist.
14
+
15
+ [devise]: https://github.com/plataformatec/devise
16
+ [original-gist]: https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
17
+
18
+
19
+ > **DISCLAIMER**: I am not José Valim, nor has he been involved in the gem bundling process. Implementation errors, if any, are mine; and contributions are welcome. -- [GB][gonzalo-bulnes]
20
+
21
+ [josevalim]: https://github.com/josevalim
22
+ [gonzalo-bulnes]: https://github.com/gonzalo-bulnes
23
+
24
+ Installation
25
+ ------------
26
+
27
+ Install [Devise][devise] with any modules you want, then add the gem to your `Gemfile`:
28
+
29
+ ```ruby
30
+ # Gemfile
31
+
32
+ gem 'simple_token_authentication', '~> 1.0' # see semver.org
33
+ ```
34
+
35
+ ### Make models token authenticatable
36
+
37
+ #### ActiveRecord
38
+
39
+ First define which model or models will be token authenticatable (typ. `User`):
40
+
41
+ ```ruby
42
+ # app/models/user.rb
43
+
44
+ class User < ActiveRecord::Base
45
+ acts_as_token_authenticatable
46
+
47
+ # Note: you can include any module you want. If available,
48
+ # token authentication will be performed before any other
49
+ # Devise authentication method.
50
+ #
51
+ # Include default devise modules. Others available are:
52
+ # :confirmable, :lockable, :timeoutable and :omniauthable
53
+ devise :invitable, :database_authenticatable,
54
+ :recoverable, :rememberable, :trackable, :validatable,
55
+ :lockable
56
+
57
+ # ...
58
+ end
59
+ ```
60
+
61
+ If the model or models you chose have no `:authentication_token` attribute, add them one (with an index):
62
+
63
+ ```bash
64
+ rails g migration add_authentication_token_to_users authentication_token:string:index
65
+ rake db:migrate
66
+ ```
67
+
68
+ #### Mongoid
69
+
70
+ Define which model or models will be token authenticatable (typ. `User`):
71
+
72
+ ```ruby
73
+ # app/models/user.rb
74
+
75
+ class User
76
+ include Mongoid::Document
77
+ # Include default devise modules. Others available are:
78
+ # :confirmable, :lockable, :timeoutable and :omniauthable
79
+ devise :database_authenticatable, :registerable,
80
+ :recoverable, :rememberable, :trackable, :validatable
81
+
82
+ ## Token Authenticatable
83
+ acts_as_token_authenticatable
84
+ field :authentication_token
85
+
86
+ # ...
87
+ end
88
+ ```
89
+
90
+ ### Allow controllers to handle token authentication
91
+
92
+ Finally define which controllers will handle token authentication (typ. `ApplicationController`) for which _token authenticatable_ models:
93
+
94
+ ```ruby
95
+ # app/controllers/application_controller.rb
96
+
97
+ class ApplicationController < ActionController::Base # or ActionController::API
98
+ # ...
99
+
100
+ acts_as_token_authentication_handler_for User
101
+
102
+ # Security note: controllers with no-CSRF protection must disable the Devise fallback,
103
+ # see #49 for details.
104
+ # acts_as_token_authentication_handler_for User, fallback_to_devise: false
105
+
106
+ # The token authentication requirement can target specific controller actions:
107
+ # acts_as_token_authentication_handler_for User, only: [:create, :update, :destroy]
108
+ # acts_as_token_authentication_handler_for User, except: [:index, :show]
109
+
110
+ # Several token authenticatable models can be handled by the same controller.
111
+ # If so, for all of them except the last, the fallback_to_devise should be disabled.
112
+ #
113
+ # Please do notice that the order of declaration defines the order of precedence.
114
+ #
115
+ # acts_as_token_authentication_handler_for Admin, fallback_to_devise: false
116
+ # acts_as_token_authentication_handler_for SpecialUser, fallback_to_devise: false
117
+ # acts_as_token_authentication_handler_for User # the last fallback is up to you
118
+
119
+ # ...
120
+ end
121
+ ```
122
+
123
+ Configuration
124
+ -------------
125
+
126
+ Some aspects of the behavior of _Simple Token Authentication_ can be customized with an initializer.
127
+ Below is an example with reasonable defaults:
128
+
129
+ ```ruby
130
+ # config/initializers/simple_token_authentication.rb
131
+
132
+ SimpleTokenAuthentication.configure do |config|
133
+
134
+ # Configure the session persistence policy after a successful sign in,
135
+ # in other words, if the authentication token acts as a signin token.
136
+ # If true, user is stored in the session and the authentication token and
137
+ # email may be provided only once.
138
+ # If false, users must provide their authentication token and email at every request.
139
+ # config.sign_in_token = false
140
+
141
+ # Configure the name of the HTTP headers watched for authentication.
142
+ #
143
+ # Default header names for a given token authenticatable entity follow the pattern:
144
+ # { entity: { authentication_token: 'X-Entity-Token', email: 'X-Entity-Email'} }
145
+ #
146
+ # When several token authenticatable models are defined, custom header names
147
+ # can be specified for none, any, or all of them.
148
+ #
149
+ # Examples
150
+ #
151
+ # Given User and SuperAdmin are token authenticatable,
152
+ # When the following configuration is used:
153
+ # `config.header_names = { super_admin: { authentication_token: 'X-Admin-Auth-Token' } }`
154
+ # Then the token authentification handler for User watches the following headers:
155
+ # `X-User-Token, X-User-Email`
156
+ # And the token authentification handler for SuperAdmin watches the following headers:
157
+ # `X-Admin-Auth-Token, X-SuperAdmin-Email`
158
+ #
159
+ # config.header_names = { user: { authentication_token: 'X-User-Token', email: 'X-User-Email' } }
160
+
161
+ end
162
+ ```
163
+
164
+ Usage
165
+ -----
166
+
167
+ ### Tokens Generation
168
+
169
+ Assuming `user` is an instance of `User`, which is _token authenticatable_: each time `user` will be saved, and `user.authentication_token.blank?` it receives a new and unique authentication token (via `Devise.friendly_token`).
170
+
171
+ ### Authentication Method 1: Query Params
172
+
173
+ You can authenticate passing the `user_email` and `user_token` params as query params:
174
+
175
+ ```
176
+ GET https://secure.example.com?user_email=alice@example.com&user_token=1G8_s7P-V-4MGojaKD7a
177
+ ```
178
+
179
+ The _token authentication handler_ (e.g. `ApplicationController`) will perform the user sign in if both are correct.
180
+
181
+ ### Authentication Method 2: Request Headers
182
+
183
+ You can also use request headers (which may be simpler when authenticating against an API):
184
+
185
+ ```
186
+ X-User-Email alice@example.com
187
+ X-User-Token 1G8_s7P-V-4MGojaKD7a
188
+ ```
189
+
190
+ In fact, you can mix both methods and provide the `user_email` with one and the `user_token` with the other, even if it would be a freak thing to do.
191
+
192
+ ### Integration with other authentication methods
193
+
194
+ If sign-in is successful, no other authentication method will be run, but if it doesn't (the authentication params were missing, or incorrect) then Devise takes control and tries to `authenticate_user!` with its own modules. That behaviour can however be modified for any controller through the **fallback_to_devise** option.
195
+
196
+ **Important**: Please do notice that controller actions whithout CSRF protection **must** disable the Devise fallback for [security reasons][csrf]. Since Rails enables CSRF protection by default, this configuration requirement should only affect controllers where you have disabled it, which may be the case of API controllers.
197
+
198
+ [csrf]: https://github.com/gonzalo-bulnes/simple_token_authentication/issues/49
199
+
200
+ Documentation
201
+ -------------
202
+
203
+ ### Frequently Asked Questions
204
+
205
+ Any question? Please don't hesitate to open a new issue to get help. I keep questions tagged to make possible to [review the open questions][open-questions], while closed questions are organized as a sort of [FAQ][faq].
206
+
207
+ [open-questions]: https://github.com/gonzalo-bulnes/simple_token_authentication/issues?labels=question&page=1&state=open
208
+ [faq]: https://github.com/gonzalo-bulnes/simple_token_authentication/issues?direction=desc&labels=question&page=1&sort=comments&state=closed
209
+
210
+ ### Changelog
211
+
212
+ Releases are commented to provide a brief [changelog][changelog].
213
+
214
+ [changelog]: https://github.com/gonzalo-bulnes/simple_token_authentication/releases
215
+
216
+ Development
217
+ -----------
218
+
219
+ ### Testing and documentation
220
+
221
+ This gem development has been test-driven since `v1.0.0`. Until `v1.5.1`, the gem behaviour was described using [Cucumber][cucumber] and [RSpec][rspec] in a dummy app generated by [Aruba][aruba]. Since `v1.5.2` it is described using Rspec alone.
222
+
223
+ RSpec [tags][tags] are used to categorize the spec examples.
224
+
225
+ Spec examples that are tagged as `public` describe aspects of the gem public API, and MAY be considered as the gem documentation.
226
+
227
+ The `private` or `protected` specs are written for development purpose only. Because they describe internal behaviour which may change at any moment without notice, they are only executed as a secondary task by the [continuous integration service][travis] and SHOULD be ignored.
228
+
229
+ Run `rake spec:public` to print the gem public documentation.
230
+
231
+ [aruba]: https://github.com/cucumber/aruba
232
+ [cucumber]: https://github.com/cucumber/cucumber-rails
233
+ [rspec]: https://www.relishapp.com/rspec/rspec-rails/docs
234
+ [tags]: https://www.relishapp.com/rspec/rspec-core/v/3-1/docs/command-line/tag-option
235
+ [travis]: https://travis-ci.org/gonzalo-bulnes/simple_token_authentication/builds
236
+
237
+ ### Contributions
238
+
239
+ Contributions are welcome! I'm not personally maintaining any [list of contributors][contributors] for now, but any PR which references us all will be welcome.
240
+
241
+ [contributors]: https://github.com/gonzalo-bulnes/simple_token_authentication/graphs/contributors
242
+
243
+ Please be sure to [review the open issues][open-questions] and contribute with your ideas or code in the issue best suited to the topic. Keeping discussions in a single place makes easier to everyone interested in that topic to keep track of the contributions.
244
+
245
+ Credits
246
+ -------
247
+
248
+ It may sound a bit redundant, but this gem wouldn't exist without [this gist][original-gist], nor without the [comments][issues] and [contributions][pulls] of many people. Thank them if you see them!
249
+
250
+ [issues]: https://github.com/gonzalo-bulnes/simple_token_authentication/issues
251
+ [pulls]: https://github.com/gonzalo-bulnes/simple_token_authentication/pulls
252
+
253
+ License
254
+ -------
255
+
256
+ Simple Token Authentication
257
+ Copyright (C) 2013, 2014 Gonzalo Bulnes Guilpain
258
+
259
+ This program is free software: you can redistribute it and/or modify
260
+ it under the terms of the GNU General Public License as published by
261
+ the Free Software Foundation, either version 3 of the License, or
262
+ (at your option) any later version.
263
+
264
+ This program is distributed in the hope that it will be useful,
265
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
266
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
267
+ GNU General Public License for more details.
268
+
269
+ You should have received a copy of the GNU General Public License
270
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,61 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'SimpleTokenAuthentication'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+
18
+ Bundler::GemHelper.install_tasks
19
+
20
+
21
+ begin
22
+ require 'inch/rake'
23
+
24
+ Inch::Rake::Suggest.new(:inch) do |suggest|
25
+ suggest.args << "--private"
26
+ suggest.args << "--pedantic"
27
+ end
28
+ rescue LoadError
29
+ desc 'Inch rake task not available'
30
+ task :inch do
31
+ abort 'Inch rake task is not available. Be sure to install inch as a gem or plugin'
32
+ end
33
+ end
34
+
35
+ begin
36
+ require 'rspec/core/rake_task'
37
+
38
+ desc 'Provide private interfaces documentation'
39
+ RSpec::Core::RakeTask.new(:spec)
40
+
41
+ namespace :spec do
42
+ desc 'Provide public interfaces documentation'
43
+ RSpec::Core::RakeTask.new(:public) do |t|
44
+ t.rspec_opts = "--tag public"
45
+ end
46
+ end
47
+
48
+ namespace :spec do
49
+ desc 'Provide private interfaces documentation for development purpose'
50
+ RSpec::Core::RakeTask.new(:development) do |t|
51
+ t.rspec_opts = "--tag protected --tag private"
52
+ end
53
+ end
54
+ rescue LoadError
55
+ desc 'RSpec rake task not available'
56
+ task :spec do
57
+ abort 'RSpec rake task is not available. Be sure to install rspec-core as a gem or plugin'
58
+ end
59
+ end
60
+
61
+ task default: ['spec:public', 'spec:development', :inch]
@@ -0,0 +1,18 @@
1
+ Documentation
2
+ =============
3
+
4
+ **Looking for the HTML features decription?**
5
+
6
+ The Cucumber features that documented the gem behaviour until `v1.5.1` constituted a robust tests suite, but they were slow and writting them was difficult enough to become a continuous bottleneck.
7
+
8
+ I decided to tackle the issue by replacing most scenarios by unit tests (see [#104][issue]), and since `v1.5.2` the gem behaviour is documented using RSpec only.
9
+
10
+ I liked the [executable documentation][exec-doc] idea, and I do not discard using Cucumber again to test _Simple Token Authentication_.
11
+ However, truth is that neither the somewhat intricated [Cucumber][cucumber] - [Aruba][aruba] - [RSpec][rspec] setup or the steps I wrote were exemplary enough to make justice to the great tool Cucumber is. So I decided to stop maintaining the features and to remove them. The RSpec test suite provides a nice [documentation][doc], and sometimes the best is a fresh start.
12
+
13
+ [exec-doc]: https://github.com/gonzalo-bulnes/simple_token_authentication/tree/v1.5.1#executable-documentation
14
+ [doc]: #testing-and-documentation
15
+ [issue]: https://github.com/gonzalo-bulnes/simple_token_authentication/issues/104
16
+ [aruba]: https://github.com/cucumber/aruba
17
+ [cucumber]: https://github.com/cucumber/cucumber-rails
18
+ [rspec]: https://www.relishapp.com/rspec/rspec-rails/docs
@@ -0,0 +1,58 @@
1
+ require 'simple_token_authentication/acts_as_token_authenticatable'
2
+ require 'simple_token_authentication/acts_as_token_authentication_handler'
3
+ require 'simple_token_authentication/configuration'
4
+
5
+ module SimpleTokenAuthentication
6
+ extend Configuration
7
+
8
+ NoAdapterAvailableError = Class.new(LoadError)
9
+
10
+ private
11
+
12
+ def self.ensure_models_can_act_as_token_authenticatables model_adapters
13
+ model_adapters.each do |model_adapter|
14
+ model_adapter.base_class.send :include, SimpleTokenAuthentication::ActsAsTokenAuthenticatable
15
+ end
16
+ end
17
+
18
+ def self.ensure_controllers_can_act_as_token_authentication_handlers controller_adapters
19
+ controller_adapters.each do |controller_adapter|
20
+ controller_adapter.base_class.send :extend, SimpleTokenAuthentication::ActsAsTokenAuthenticationHandler
21
+ end
22
+ end
23
+
24
+ # Private: Load the available adapters.
25
+ #
26
+ # adapters_short_names - Array of names of the adapters to load if available
27
+ #
28
+ # Example
29
+ #
30
+ # load_available_adapters ['unavailable_adapter', 'available_adapter']
31
+ # # => [SimpleTokenAuthentication::Adapters::AvailableAdapter]
32
+ #
33
+ # Returns an Array of available adapters
34
+ def self.load_available_adapters adapters_short_names
35
+ available_adapters = adapters_short_names.collect do |short_name|
36
+ adapter_name = "simple_token_authentication/adapters/#{short_name}_adapter"
37
+ if adapter_dependency_fulfilled?(short_name) && require(adapter_name)
38
+ adapter_name.camelize.constantize
39
+ end
40
+ end
41
+ available_adapters.compact!
42
+
43
+ # stop here if dependencies are missing or no adequate adapters are present
44
+ raise SimpleTokenAuthentication::NoAdapterAvailableError if available_adapters.empty?
45
+
46
+ available_adapters
47
+ end
48
+
49
+ def self.adapter_dependency_fulfilled? adapter_short_name
50
+ Object.qualified_const_defined?(SimpleTokenAuthentication.adapters_dependencies[adapter_short_name])
51
+ end
52
+
53
+ available_model_adapters = load_available_adapters SimpleTokenAuthentication.model_adapters
54
+ ensure_models_can_act_as_token_authenticatables available_model_adapters
55
+
56
+ available_controller_adapters = load_available_adapters SimpleTokenAuthentication.controller_adapters
57
+ ensure_controllers_can_act_as_token_authentication_handlers available_controller_adapters
58
+ end
@@ -0,0 +1,49 @@
1
+ require 'active_support/concern'
2
+ require 'simple_token_authentication/token_generator'
3
+
4
+ module SimpleTokenAuthentication
5
+ module ActsAsTokenAuthenticatable
6
+ extend ::ActiveSupport::Concern
7
+
8
+ # Please see https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
9
+ # before editing this file, the discussion is very interesting.
10
+
11
+ included do
12
+ private :generate_authentication_token
13
+ private :token_suitable?
14
+ private :token_generator
15
+ end
16
+
17
+ # Set an authentication token if missing
18
+ #
19
+ # Because it is intended to be used as a filter,
20
+ # this method is -and should be kept- idempotent.
21
+ def ensure_authentication_token
22
+ if authentication_token.blank?
23
+ self.authentication_token = generate_authentication_token(token_generator)
24
+ end
25
+ end
26
+
27
+ def generate_authentication_token(token_generator)
28
+ loop do
29
+ token = token_generator.generate_token
30
+ break token if token_suitable?(token)
31
+ end
32
+ end
33
+
34
+ def token_suitable?(token)
35
+ self.class.where(authentication_token: token).count == 0
36
+ end
37
+
38
+ # Private: Get one (always the same) object which behaves as a token generator
39
+ def token_generator
40
+ @token_generator ||= TokenGenerator.new
41
+ end
42
+
43
+ module ClassMethods
44
+ def acts_as_token_authenticatable(options = {})
45
+ before_save :ensure_authentication_token
46
+ end
47
+ end
48
+ end
49
+ end