devise-token_authenticatable 0.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/devise-token_authenticatable.gemspec +36 -0
- data/lib/devise-token_authenticatable.rb +1 -0
- data/lib/devise/token_authenticatable.rb +27 -0
- data/lib/devise/token_authenticatable/model.rb +90 -0
- data/lib/devise/token_authenticatable/strategy.rb +102 -0
- data/lib/devise/token_authenticatable/version.rb +5 -0
- data/spec/factories/admin.rb +24 -0
- data/spec/factories/user.rb +25 -0
- data/spec/models/devise/token_authenticatable/model_spec.rb +79 -0
- data/spec/requests/devise/token_authenticatable/strategy_spec.rb +340 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/helpers.rb +33 -0
- data/spec/support/integration.rb +8 -0
- data/spec/support/rails_app.rb +19 -0
- data/spec/support/rails_app/Rakefile +6 -0
- data/spec/support/rails_app/app/controllers/admins/sessions_controller.rb +6 -0
- data/spec/support/rails_app/app/controllers/admins_controller.rb +11 -0
- data/spec/support/rails_app/app/controllers/application_controller.rb +9 -0
- data/spec/support/rails_app/app/controllers/home_controller.rb +25 -0
- data/spec/support/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
- data/spec/support/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
- data/spec/support/rails_app/app/controllers/users_controller.rb +31 -0
- data/spec/support/rails_app/app/mailers/users/mailer.rb +12 -0
- data/spec/support/rails_app/app/models/admin.rb +9 -0
- data/spec/support/rails_app/app/models/user.rb +25 -0
- data/spec/support/rails_app/app/views/users/index.html.erb +1 -0
- data/spec/support/rails_app/config.ru +4 -0
- data/spec/support/rails_app/config/database.yml +11 -0
- data/spec/support/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/support/rails_app/config/initializers/devise.rb +173 -0
- data/spec/support/rails_app/config/initializers/inflections.rb +2 -0
- data/spec/support/rails_app/config/initializers/secret_token.rb +4 -0
- data/spec/support/rails_app/config/routes.rb +104 -0
- data/spec/support/rails_app/db/migrate/20100401102949_create_tables.rb +74 -0
- data/spec/support/rails_app/db/schema.rb +52 -0
- data/spec/support/rails_app/public/404.html +26 -0
- data/spec/support/rails_app/public/422.html +26 -0
- data/spec/support/rails_app/public/500.html +26 -0
- data/spec/support/rails_app/public/favicon.ico +0 -0
- data/spec/support/session_helper.rb +27 -0
- metadata +289 -0
data/.gitignore
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
*.log
|
4
|
+
.bundle
|
5
|
+
.config
|
6
|
+
.rspec
|
7
|
+
.rspec-local
|
8
|
+
.ruby-version
|
9
|
+
.yardoc
|
10
|
+
Gemfile.lock
|
11
|
+
InstalledFiles
|
12
|
+
_yardoc
|
13
|
+
coverage
|
14
|
+
doc/
|
15
|
+
lib/bundler/man
|
16
|
+
pkg
|
17
|
+
rdoc
|
18
|
+
spec/reports
|
19
|
+
test/tmp
|
20
|
+
test/version_tmp
|
21
|
+
tmp
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Sebastian Oelke
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Devise::TokenAuthenticatable
|
2
|
+
|
3
|
+
**Note that this gem is not ready for usage, yet!**
|
4
|
+
|
5
|
+
TODO: Write a gem description
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'devise-token_authenticatable'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install devise-token_authenticatable
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'devise/token_authenticatable/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "devise-token_authenticatable"
|
8
|
+
spec.version = Devise::TokenAuthenticatable::VERSION.dup
|
9
|
+
spec.platform = Gem::Platform::RUBY
|
10
|
+
spec.authors = ["Sebastian Oelke"]
|
11
|
+
spec.email = ["dev@sohleeatsworld.de"]
|
12
|
+
spec.description = %q{This gem provides the extracted Token Authenticatable module of devise.
|
13
|
+
It enables the user to sign in via an authentication token. This token
|
14
|
+
can be given via a query string or HTTP Basic Authentication.}
|
15
|
+
spec.summary = %q{Provides authentication based on an authentication token for devise 3.2 and up.}
|
16
|
+
spec.homepage = "https://github.com/baschtl/devise-token_authenticatable"
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files`.split($/)
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
|
25
|
+
spec.add_dependency "devise", "~> 3.2.0"
|
26
|
+
|
27
|
+
spec.add_development_dependency "activerecord", ">= 3.2"
|
28
|
+
spec.add_development_dependency "actionmailer", ">= 3.2"
|
29
|
+
spec.add_development_dependency "rspec-rails"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "factory_girl_rails"
|
32
|
+
spec.add_development_dependency "timecop"
|
33
|
+
spec.add_development_dependency "sqlite3", "~> 1.3"
|
34
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
35
|
+
spec.add_development_dependency "rake"
|
36
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'devise/token_authenticatable'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "devise/token_authenticatable/strategy"
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module TokenAuthenticatable
|
5
|
+
|
6
|
+
# Authentication token params key name of choice. E.g. /users/sign_in?some_key=...
|
7
|
+
mattr_accessor :token_authentication_key
|
8
|
+
@@token_authentication_key = :auth_token
|
9
|
+
|
10
|
+
# Enable the configuration of the TokenAuthenticatable
|
11
|
+
# strategy with a block:
|
12
|
+
#
|
13
|
+
# Devise::TokenAuthenticatable.setup do |config|
|
14
|
+
# config.token_authentication_key = :other_key
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
def self.setup
|
18
|
+
yield self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Register TokenAuthenticatable module in Devise.
|
24
|
+
Devise::add_module :token_authenticatable,
|
25
|
+
model: 'devise/token_authenticatable/model',
|
26
|
+
strategy: true,
|
27
|
+
no_input: true
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Devise
|
2
|
+
module Models
|
3
|
+
# The TokenAuthenticatable module is responsible for generating an authentication token and
|
4
|
+
# validating the authenticity of the same while signing in.
|
5
|
+
#
|
6
|
+
# This module only provides a few helpers to help you manage the token, but it is up to you
|
7
|
+
# to choose how to use it. For example, if you want to have a new token every time the user
|
8
|
+
# saves his account, you can do the following:
|
9
|
+
#
|
10
|
+
# before_save :reset_authentication_token
|
11
|
+
#
|
12
|
+
# On the other hand, if you want to generate token unless one exists, you should use instead:
|
13
|
+
#
|
14
|
+
# before_save :ensure_authentication_token
|
15
|
+
#
|
16
|
+
# If you want to delete the token after it is used, you can do so in the
|
17
|
+
# after_token_authentication callback.
|
18
|
+
#
|
19
|
+
# == APIs
|
20
|
+
#
|
21
|
+
# If you are using token authentication with APIs and using trackable. Every
|
22
|
+
# request will be considered as a new sign in (since there is no session in
|
23
|
+
# APIs). You can disable this by creating a before filter as follow:
|
24
|
+
#
|
25
|
+
# before_filter :skip_trackable
|
26
|
+
#
|
27
|
+
# def skip_trackable
|
28
|
+
# request.env['devise.skip_trackable'] = true
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# == Options
|
32
|
+
#
|
33
|
+
# TokenAuthenticatable adds the following options to devise_for:
|
34
|
+
#
|
35
|
+
# * +token_authentication_key+: Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
|
36
|
+
#
|
37
|
+
module TokenAuthenticatable
|
38
|
+
extend ActiveSupport::Concern
|
39
|
+
|
40
|
+
def self.required_fields(klass)
|
41
|
+
[:authentication_token]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Generate new authentication token (a.k.a. "single access token").
|
45
|
+
def reset_authentication_token
|
46
|
+
self.authentication_token = self.class.authentication_token
|
47
|
+
end
|
48
|
+
|
49
|
+
# Generate new authentication token and save the record.
|
50
|
+
def reset_authentication_token!
|
51
|
+
reset_authentication_token
|
52
|
+
save(:validate => false)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Generate authentication token unless already exists.
|
56
|
+
def ensure_authentication_token
|
57
|
+
reset_authentication_token if authentication_token.blank?
|
58
|
+
end
|
59
|
+
|
60
|
+
# Generate authentication token unless already exists and save the record.
|
61
|
+
def ensure_authentication_token!
|
62
|
+
reset_authentication_token! if authentication_token.blank?
|
63
|
+
end
|
64
|
+
|
65
|
+
# Hook called after token authentication.
|
66
|
+
def after_token_authentication
|
67
|
+
end
|
68
|
+
|
69
|
+
def expire_auth_token_on_timeout
|
70
|
+
self.class.expire_auth_token_on_timeout
|
71
|
+
end
|
72
|
+
|
73
|
+
module ClassMethods
|
74
|
+
def find_for_token_authentication(conditions)
|
75
|
+
find_for_authentication(:authentication_token => conditions[Devise::TokenAuthenticatable.token_authentication_key])
|
76
|
+
end
|
77
|
+
|
78
|
+
# Generate a token checking if one does not already exist in the database.
|
79
|
+
def authentication_token
|
80
|
+
loop do
|
81
|
+
token = Devise.friendly_token
|
82
|
+
break token unless to_adapter.find_first({ :authentication_token => token })
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
Devise::Models.config(self, :token_authentication_key, :expire_auth_token_on_timeout)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'devise/strategies/base'
|
2
|
+
|
3
|
+
module Devise
|
4
|
+
module Strategies
|
5
|
+
#
|
6
|
+
# The +TokenAuthenticatable+ strategy was extracted from Devise 3.1.0. Its purpose is
|
7
|
+
# to provide the deprecated functionality of the +TokenAuthenticatable+ strategy. The
|
8
|
+
# following description was adapted accordingly.
|
9
|
+
#
|
10
|
+
# See: https://github.com/plataformatec/devise/blob/v3.1/lib/devise/strategies/token_authenticatable.rb
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# Strategy for signing in a user, based on a authenticatable token. This works for both params
|
14
|
+
# and http. For the former, all you need to do is to pass the params in the URL:
|
15
|
+
#
|
16
|
+
# http://myapp.example.com/?user_token=SECRET
|
17
|
+
#
|
18
|
+
# For headers, you can use basic authentication passing the token as username and
|
19
|
+
# blank password. Since some clients may require a password, you can pass "X" as
|
20
|
+
# password and it will simply be ignored.
|
21
|
+
#
|
22
|
+
# You may also pass the token using the Token authentication mechanism provided
|
23
|
+
# by Rails: http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
|
24
|
+
# The token options are stored in request.env['devise.token_options']
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# Changes regarding the original +TokenAuthenticatable+ implementation:
|
28
|
+
#
|
29
|
+
# The private method +remember_me?+ in +TokenAuthenticatable+ returns +false+.
|
30
|
+
# For +TokenAuthenticatable+ this method was removed. This results in the
|
31
|
+
# usage of the default implementation in +Authenticatable+.
|
32
|
+
#
|
33
|
+
class TokenAuthenticatable < Authenticatable
|
34
|
+
def store?
|
35
|
+
super && !mapping.to.skip_session_storage.include?(:token_auth)
|
36
|
+
end
|
37
|
+
|
38
|
+
def valid?
|
39
|
+
super || valid_for_token_auth?
|
40
|
+
end
|
41
|
+
|
42
|
+
def authenticate!
|
43
|
+
resource = mapping.to.find_for_token_authentication(authentication_hash)
|
44
|
+
return fail(:invalid_token) unless resource
|
45
|
+
|
46
|
+
if validate(resource)
|
47
|
+
resource.after_token_authentication
|
48
|
+
success!(resource)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# Token Authenticatable can be authenticated with params in any controller and any verb.
|
55
|
+
def valid_params_request?
|
56
|
+
true
|
57
|
+
end
|
58
|
+
|
59
|
+
# Check if the model accepts this strategy as token authenticatable.
|
60
|
+
def token_authenticatable?
|
61
|
+
mapping.to.http_authenticatable?(:token_options)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check if this is strategy is valid for token authentication by:
|
65
|
+
#
|
66
|
+
# * Validating if the model allows http token authentication;
|
67
|
+
# * If the http auth token exists;
|
68
|
+
# * If all authentication keys are present;
|
69
|
+
#
|
70
|
+
def valid_for_token_auth?
|
71
|
+
token_authenticatable? && auth_token.present? && with_authentication_hash(:token_auth, token_auth_hash)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Extract the auth token from the request
|
75
|
+
def auth_token
|
76
|
+
@auth_token ||= ActionController::HttpAuthentication::Token.token_and_options(request)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Extract a hash with attributes:values from the auth_token
|
80
|
+
def token_auth_hash
|
81
|
+
request.env['devise.token_options'] = auth_token.last
|
82
|
+
{ authentication_keys.first => auth_token.first }
|
83
|
+
end
|
84
|
+
|
85
|
+
# Try both scoped and non scoped keys
|
86
|
+
def params_auth_hash
|
87
|
+
if params[scope].kind_of?(Hash) && params[scope].has_key?(authentication_keys.first)
|
88
|
+
params[scope]
|
89
|
+
else
|
90
|
+
params
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Overwrite authentication keys to use token_authentication_key.
|
95
|
+
def authentication_keys
|
96
|
+
@authentication_keys ||= [Devise::TokenAuthenticatable.token_authentication_key]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
|
3
|
+
factory :admin do
|
4
|
+
sequence(:email) { |n| "admin#{n}@domain.com" }
|
5
|
+
password 'some_password'
|
6
|
+
password_confirmation 'some_password'
|
7
|
+
|
8
|
+
ignore do
|
9
|
+
confirm_account true
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:create) do |u, evaluator|
|
13
|
+
u.confirm! if evaluator.confirm_account
|
14
|
+
end
|
15
|
+
|
16
|
+
trait :with_reset_password_token do
|
17
|
+
reset_password_token { SecureRandom.hex }
|
18
|
+
end
|
19
|
+
|
20
|
+
trait :with_authentication_token do
|
21
|
+
authentication_token { SecureRandom.hex }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
|
3
|
+
factory :user do
|
4
|
+
username 'testuser'
|
5
|
+
sequence(:email) { |n| "user#{n}@domain.com" }
|
6
|
+
password 'some_password'
|
7
|
+
password_confirmation 'some_password'
|
8
|
+
|
9
|
+
ignore do
|
10
|
+
confirm_account true
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:create) do |u, evaluator|
|
14
|
+
u.confirm! if evaluator.confirm_account
|
15
|
+
end
|
16
|
+
|
17
|
+
trait :with_reset_password_token do
|
18
|
+
reset_password_token { SecureRandom.hex }
|
19
|
+
end
|
20
|
+
|
21
|
+
trait :with_authentication_token do
|
22
|
+
authentication_token { SecureRandom.hex }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
##
|
4
|
+
# If a model that is plain token authenticatable should be tested with
|
5
|
+
# this shared example the corresponding factory has to provide a trait
|
6
|
+
# +:with_authentication_token+ that sets the attribute +authentication_token+.
|
7
|
+
#
|
8
|
+
# See spec/factories/account.rb for an example.
|
9
|
+
#
|
10
|
+
shared_examples "plain token authenticatable" do
|
11
|
+
|
12
|
+
context "instance methods" do
|
13
|
+
|
14
|
+
describe "#reset_authentication_token" do
|
15
|
+
let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) }
|
16
|
+
|
17
|
+
it "should reset authentication token" do
|
18
|
+
expect { entity.reset_authentication_token }.to change { entity.authentication_token }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#ensure_authentication_token" do
|
23
|
+
|
24
|
+
context "with existing authentication token" do
|
25
|
+
let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) }
|
26
|
+
|
27
|
+
it "should not change the authentication token" do
|
28
|
+
expect { entity.ensure_authentication_token }.to_not change { entity.authentication_token }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "without existing authentication token" do
|
33
|
+
let(:entity) { create(described_class.name.underscore.to_sym) }
|
34
|
+
|
35
|
+
it "should create an authentication token" do
|
36
|
+
entity.authentication_token = nil
|
37
|
+
expect { entity.ensure_authentication_token }.to change { entity.authentication_token }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "class methods" do
|
44
|
+
|
45
|
+
describe "#find_for_authentication_token" do
|
46
|
+
let(:entity) { create(described_class.name.underscore.to_sym, :with_authentication_token) }
|
47
|
+
|
48
|
+
it "should authenticate a valid entity with authentication token and return it" do
|
49
|
+
authenticated_entity = described_class.find_for_token_authentication(auth_token: entity.authentication_token)
|
50
|
+
expect(entity.authentication_token).to eq(authenticated_entity.authentication_token)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return nil when authenticating an invalid entity by authentication token" do
|
54
|
+
authenticated_entity = described_class.find_for_token_authentication(auth_token: entity.authentication_token.reverse)
|
55
|
+
expect(authenticated_entity).to be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should not be subject to injection" do
|
59
|
+
entity2 = create(described_class.name.underscore.to_sym, :with_authentication_token)
|
60
|
+
|
61
|
+
authenticated_entity = described_class.find_for_token_authentication(auth_token: { '$ne' => entity.authentication_token })
|
62
|
+
expect(authenticated_entity).to be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#required_fields" do
|
67
|
+
|
68
|
+
it "should contain the fields that Devise uses" do
|
69
|
+
expect(Devise::Models::TokenAuthenticatable.required_fields(described_class)).to eq([
|
70
|
+
:authentication_token
|
71
|
+
])
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe User do
|
78
|
+
it_behaves_like "plain token authenticatable"
|
79
|
+
end
|