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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +270 -0
- data/Rakefile +61 -0
- data/doc/README.md +18 -0
- data/lib/simple_token_authentication.rb +58 -0
- data/lib/simple_token_authentication/acts_as_token_authenticatable.rb +49 -0
- data/lib/simple_token_authentication/acts_as_token_authentication_handler.rb +22 -0
- data/lib/simple_token_authentication/adapter.rb +7 -0
- data/lib/simple_token_authentication/adapters/active_record_adapter.rb +14 -0
- data/lib/simple_token_authentication/adapters/mongoid_adapter.rb +14 -0
- data/lib/simple_token_authentication/adapters/rails_adapter.rb +14 -0
- data/lib/simple_token_authentication/adapters/rails_api_adapter.rb +18 -0
- data/lib/simple_token_authentication/configuration.rb +45 -0
- data/lib/simple_token_authentication/entities_manager.rb +10 -0
- data/lib/simple_token_authentication/entity.rb +64 -0
- data/lib/simple_token_authentication/fallback_authentication_handler.rb +11 -0
- data/lib/simple_token_authentication/sign_in_handler.rb +19 -0
- data/lib/simple_token_authentication/token_authentication_handler.rb +149 -0
- data/lib/simple_token_authentication/token_comparator.rb +20 -0
- data/lib/simple_token_authentication/token_generator.rb +9 -0
- data/lib/simple_token_authentication/version.rb +3 -0
- data/lib/tasks/simple_token_authentication_tasks.rake +4 -0
- data/spec/configuration/action_controller_callbacks_options_spec.rb +53 -0
- data/spec/configuration/fallback_to_devise_option_spec.rb +128 -0
- data/spec/configuration/header_names_option_spec.rb +463 -0
- data/spec/configuration/sign_in_token_option_spec.rb +92 -0
- data/spec/lib/simple_token_authentication/acts_as_token_authenticatable_spec.rb +108 -0
- data/spec/lib/simple_token_authentication/acts_as_token_authentication_handler_spec.rb +127 -0
- data/spec/lib/simple_token_authentication/adapter_spec.rb +19 -0
- data/spec/lib/simple_token_authentication/adapters/active_record_adapter_spec.rb +21 -0
- data/spec/lib/simple_token_authentication/adapters/mongoid_adapter_spec.rb +21 -0
- data/spec/lib/simple_token_authentication/adapters/rails_adapter_spec.rb +21 -0
- data/spec/lib/simple_token_authentication/adapters/rails_api_adapter_spec.rb +43 -0
- data/spec/lib/simple_token_authentication/configuration_spec.rb +133 -0
- data/spec/lib/simple_token_authentication/entities_manager_spec.rb +67 -0
- data/spec/lib/simple_token_authentication/entity_spec.rb +190 -0
- data/spec/lib/simple_token_authentication/errors_spec.rb +8 -0
- data/spec/lib/simple_token_authentication/fallback_authentication_handler_spec.rb +24 -0
- data/spec/lib/simple_token_authentication/sign_in_handler_spec.rb +43 -0
- data/spec/lib/simple_token_authentication/token_authentication_handler_spec.rb +351 -0
- data/spec/lib/simple_token_authentication/token_comparator_spec.rb +19 -0
- data/spec/lib/simple_token_authentication/token_generator_spec.rb +19 -0
- data/spec/lib/simple_token_authentication_spec.rb +181 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/dummy_classes_helper.rb +80 -0
- data/spec/support/spec_for_adapter.rb +10 -0
- data/spec/support/spec_for_authentication_handler_interface.rb +8 -0
- data/spec/support/spec_for_configuration_option_interface.rb +28 -0
- data/spec/support/spec_for_entities_manager_interface.rb +8 -0
- data/spec/support/spec_for_sign_in_handler_interface.rb +8 -0
- data/spec/support/spec_for_token_comparator_interface.rb +8 -0
- data/spec/support/spec_for_token_generator_interface.rb +8 -0
- data/spec/support/specs_for_token_authentication_handler_interface.rb +8 -0
- metadata +250 -0
data/README.md
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
Simple Token Authentication
|
2
|
+
===========================
|
3
|
+
|
4
|
+
[](http://badge.fury.io/rb/simple_token_authentication)
|
5
|
+
[](https://travis-ci.org/gonzalo-bulnes/simple_token_authentication)
|
6
|
+
[](https://codeclimate.com/github/gonzalo-bulnes/simple_token_authentication)
|
7
|
+
[](https://gemnasium.com/gonzalo-bulnes/simple_token_authentication)
|
8
|
+
[](https://hakiri.io/github/gonzalo-bulnes/simple_token_authentication/master)
|
9
|
+
[](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/>.
|
data/Rakefile
ADDED
@@ -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]
|
data/doc/README.md
ADDED
@@ -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
|