stn-simple_token_authentication 1.7.1

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 (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