mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-09 14:58:05 -05:00
Get rid of token authentication
This commit is contained in:
@@ -11,7 +11,6 @@ en:
|
|||||||
already_authenticated: "You are already signed in."
|
already_authenticated: "You are already signed in."
|
||||||
inactive: "Your account is not activated yet."
|
inactive: "Your account is not activated yet."
|
||||||
invalid: "Invalid email or password."
|
invalid: "Invalid email or password."
|
||||||
invalid_token: "Invalid authentication token."
|
|
||||||
locked: "Your account is locked."
|
locked: "Your account is locked."
|
||||||
not_found_in_database: "Invalid email or password."
|
not_found_in_database: "Invalid email or password."
|
||||||
timeout: "Your session expired. Please sign in again to continue."
|
timeout: "Your session expired. Please sign in again to continue."
|
||||||
|
|||||||
@@ -84,11 +84,6 @@ module Devise
|
|||||||
devise_modules_hook! do
|
devise_modules_hook! do
|
||||||
include Devise::Models::Authenticatable
|
include Devise::Models::Authenticatable
|
||||||
|
|
||||||
if selected_modules.include?(:token_authenticatable)
|
|
||||||
ActiveSupport::Deprecation.warn "devise :token_authenticatable is deprecated. " \
|
|
||||||
"Please check Devise 3.1 release notes for more information on how to upgrade."
|
|
||||||
end
|
|
||||||
|
|
||||||
selected_modules.each do |m|
|
selected_modules.each do |m|
|
||||||
mod = Devise::Models.const_get(m.to_s.classify)
|
mod = Devise::Models.const_get(m.to_s.classify)
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,7 @@ module Devise
|
|||||||
# It also accepts an array specifying the strategies that should allow params authentication.
|
# It also accepts an array specifying the strategies that should allow params authentication.
|
||||||
#
|
#
|
||||||
# * +skip_session_storage+: By default Devise will store the user in session.
|
# * +skip_session_storage+: By default Devise will store the user in session.
|
||||||
# You can skip storage for http and token auth by appending values to array:
|
# By default is set to :skip_session_storage => [:http_auth].
|
||||||
# :skip_session_storage => [:token_auth] or :skip_session_storage => [:http_auth, :token_auth],
|
|
||||||
# by default is set to :skip_session_storage => [:http_auth].
|
|
||||||
#
|
#
|
||||||
# == active_for_authentication?
|
# == active_for_authentication?
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
require 'devise/strategies/token_authenticatable'
|
|
||||||
|
|
||||||
module Devise
|
|
||||||
module Models
|
|
||||||
# The TokenAuthenticatable module is responsible for generating an authentication token and
|
|
||||||
# validating the authenticity of the same while signing in.
|
|
||||||
#
|
|
||||||
# This module only provides a few helpers to help you manage the token, but it is up to you
|
|
||||||
# to choose how to use it. For example, if you want to have a new token every time the user
|
|
||||||
# saves his account, you can do the following:
|
|
||||||
#
|
|
||||||
# before_save :reset_authentication_token
|
|
||||||
#
|
|
||||||
# On the other hand, if you want to generate token unless one exists, you should use instead:
|
|
||||||
#
|
|
||||||
# before_save :ensure_authentication_token
|
|
||||||
#
|
|
||||||
# If you want to delete the token after it is used, you can do so in the
|
|
||||||
# after_token_authentication callback.
|
|
||||||
#
|
|
||||||
# == APIs
|
|
||||||
#
|
|
||||||
# If you are using token authentication with APIs and using trackable. Every
|
|
||||||
# request will be considered as a new sign in (since there is no session in
|
|
||||||
# APIs). You can disable this by creating a before filter as follow:
|
|
||||||
#
|
|
||||||
# before_filter :skip_trackable
|
|
||||||
#
|
|
||||||
# def skip_trackable
|
|
||||||
# request.env['devise.skip_trackable'] = true
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# == Options
|
|
||||||
#
|
|
||||||
# TokenAuthenticatable adds the following options to devise_for:
|
|
||||||
#
|
|
||||||
# * +token_authentication_key+: Defines name of the authentication token params key. E.g. /users/sign_in?some_key=...
|
|
||||||
#
|
|
||||||
module TokenAuthenticatable
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
def self.required_fields(klass)
|
|
||||||
[:authentication_token]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate new authentication token (a.k.a. "single access token").
|
|
||||||
def reset_authentication_token
|
|
||||||
self.authentication_token = self.class.authentication_token
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate new authentication token and save the record.
|
|
||||||
def reset_authentication_token!
|
|
||||||
reset_authentication_token
|
|
||||||
save(:validate => false)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate authentication token unless already exists.
|
|
||||||
def ensure_authentication_token
|
|
||||||
reset_authentication_token if authentication_token.blank?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate authentication token unless already exists and save the record.
|
|
||||||
def ensure_authentication_token!
|
|
||||||
reset_authentication_token! if authentication_token.blank?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Hook called after token authentication.
|
|
||||||
def after_token_authentication
|
|
||||||
end
|
|
||||||
|
|
||||||
def expire_auth_token_on_timeout
|
|
||||||
self.class.expire_auth_token_on_timeout
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
def find_for_token_authentication(conditions)
|
|
||||||
find_for_authentication(:authentication_token => conditions[token_authentication_key])
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate a token checking if one does not already exist in the database.
|
|
||||||
def authentication_token
|
|
||||||
loop do
|
|
||||||
token = Devise.friendly_token
|
|
||||||
break token unless to_adapter.find_first({ :authentication_token => token })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Devise::Models.config(self, :token_authentication_key, :expire_auth_token_on_timeout)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -5,7 +5,6 @@ Devise.with_options :model => true do |d|
|
|||||||
d.with_options :strategy => true do |s|
|
d.with_options :strategy => true do |s|
|
||||||
routes = [nil, :new, :destroy]
|
routes = [nil, :new, :destroy]
|
||||||
s.add_module :database_authenticatable, :controller => :sessions, :route => { :session => routes }
|
s.add_module :database_authenticatable, :controller => :sessions, :route => { :session => routes }
|
||||||
s.add_module :token_authenticatable, :controller => :sessions, :route => { :session => routes }, :no_input => true
|
|
||||||
s.add_module :rememberable, :no_input => true
|
s.add_module :rememberable, :no_input => true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
require 'devise/strategies/base'
|
|
||||||
|
|
||||||
module Devise
|
|
||||||
module Strategies
|
|
||||||
# Strategy for signing in a user, based on a authenticatable token. This works for both params
|
|
||||||
# and http. For the former, all you need to do is to pass the params in the URL:
|
|
||||||
#
|
|
||||||
# http://myapp.example.com/?user_token=SECRET
|
|
||||||
#
|
|
||||||
# For headers, you can use basic authentication passing the token as username and
|
|
||||||
# blank password. Since some clients may require a password, you can pass "X" as
|
|
||||||
# password and it will simply be ignored.
|
|
||||||
#
|
|
||||||
# You may also pass the token using the Token authentication mechanism provided
|
|
||||||
# by Rails: http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
|
|
||||||
# The token options are stored in request.env['devise.token_options']
|
|
||||||
class TokenAuthenticatable < Authenticatable
|
|
||||||
def store?
|
|
||||||
super && !mapping.to.skip_session_storage.include?(:token_auth)
|
|
||||||
end
|
|
||||||
|
|
||||||
def valid?
|
|
||||||
super || valid_for_token_auth?
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate!
|
|
||||||
resource = mapping.to.find_for_token_authentication(authentication_hash)
|
|
||||||
return fail(:invalid_token) unless resource
|
|
||||||
|
|
||||||
if validate(resource)
|
|
||||||
resource.after_token_authentication
|
|
||||||
success!(resource)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Token Authenticatable can be authenticated with params in any controller and any verb.
|
|
||||||
def valid_params_request?
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
# Do not use remember_me behavior with token.
|
|
||||||
def remember_me?
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if the model accepts this strategy as token authenticatable.
|
|
||||||
def token_authenticatable?
|
|
||||||
mapping.to.http_authenticatable?(:token_options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if this is strategy is valid for token authentication by:
|
|
||||||
#
|
|
||||||
# * Validating if the model allows http token authentication;
|
|
||||||
# * If the http auth token exists;
|
|
||||||
# * If all authentication keys are present;
|
|
||||||
#
|
|
||||||
def valid_for_token_auth?
|
|
||||||
token_authenticatable? && auth_token.present? && with_authentication_hash(:token_auth, token_auth_hash)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extract the auth token from the request
|
|
||||||
def auth_token
|
|
||||||
@auth_token ||= ActionController::HttpAuthentication::Token.token_and_options(request)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extract a hash with attributes:values from the auth_token
|
|
||||||
def token_auth_hash
|
|
||||||
request.env['devise.token_options'] = auth_token.last
|
|
||||||
{ authentication_keys.first => auth_token.first }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Try both scoped and non scoped keys
|
|
||||||
def params_auth_hash
|
|
||||||
if params[scope].kind_of?(Hash) && params[scope].has_key?(authentication_keys.first)
|
|
||||||
params[scope]
|
|
||||||
else
|
|
||||||
params
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Overwrite authentication keys to use token_authentication_key.
|
|
||||||
def authentication_keys
|
|
||||||
@authentication_keys ||= [mapping.to.token_authentication_key]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)
|
|
||||||
@@ -47,9 +47,6 @@ module Mongoid
|
|||||||
# field :failed_attempts, :type => Integer, :default => 0 # Only if lock strategy is :failed_attempts
|
# field :failed_attempts, :type => Integer, :default => 0 # Only if lock strategy is :failed_attempts
|
||||||
# field :unlock_token, :type => String # Only if unlock strategy is :email or :both
|
# field :unlock_token, :type => String # Only if unlock strategy is :email or :both
|
||||||
# field :locked_at, :type => Time
|
# field :locked_at, :type => Time
|
||||||
|
|
||||||
## Token authenticatable
|
|
||||||
# field :authentication_token, :type => String
|
|
||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -56,12 +56,9 @@ Devise.setup do |config|
|
|||||||
|
|
||||||
# Tell if authentication through HTTP Auth is enabled. False by default.
|
# Tell if authentication through HTTP Auth is enabled. False by default.
|
||||||
# It can be set to an array that will enable http authentication only for the
|
# It can be set to an array that will enable http authentication only for the
|
||||||
# given strategies, for example, `config.http_authenticatable = [:token]` will
|
# given strategies, for example, `config.http_authenticatable = [:database]` will
|
||||||
# enable it only for token authentication. The supported strategies are:
|
# enable it only for database authentication. The supported strategies are:
|
||||||
# :database = Support basic authentication with authentication key + password
|
# :database = Support basic authentication with authentication key + password
|
||||||
# :token = Support basic authentication with token authentication key
|
|
||||||
# :token_options = Support token authentication with options as defined in
|
|
||||||
# http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
|
|
||||||
# config.http_authenticatable = false
|
# config.http_authenticatable = false
|
||||||
|
|
||||||
# If http headers should be returned for AJAX requests. True by default.
|
# If http headers should be returned for AJAX requests. True by default.
|
||||||
@@ -76,7 +73,7 @@ Devise.setup do |config|
|
|||||||
# config.paranoid = true
|
# config.paranoid = true
|
||||||
|
|
||||||
# By default Devise will store the user in session. You can skip storage for
|
# By default Devise will store the user in session. You can skip storage for
|
||||||
# :http_auth and :token_auth by adding those symbols to the array below.
|
# particular strategies by setting this option.
|
||||||
# Notice that if you are skipping storage for all authentication paths, you
|
# Notice that if you are skipping storage for all authentication paths, you
|
||||||
# may want to disable generating routes to Devise's sessions controller by
|
# may want to disable generating routes to Devise's sessions controller by
|
||||||
# passing :skip => :sessions to `devise_for` in your config/routes.rb
|
# passing :skip => :sessions to `devise_for` in your config/routes.rb
|
||||||
@@ -196,10 +193,6 @@ Devise.setup do |config|
|
|||||||
# Require the `devise-encryptable` gem when using anything other than bcrypt
|
# Require the `devise-encryptable` gem when using anything other than bcrypt
|
||||||
# config.encryptor = :sha512
|
# config.encryptor = :sha512
|
||||||
|
|
||||||
# ==> Configuration for :token_authenticatable
|
|
||||||
# Defines name of the authentication token params key
|
|
||||||
# config.token_authentication_key = :auth_token
|
|
||||||
|
|
||||||
# ==> Scopes configuration
|
# ==> Scopes configuration
|
||||||
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
# Turn scoped views on. Before rendering "sessions/new", it will first check for
|
||||||
# "users/sessions/new". It's turned off by default because it's slower if you
|
# "users/sessions/new". It's turned off by default because it's slower if you
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class HelpersTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test 'require no authentication tests current mapping' do
|
test 'require no authentication tests current mapping' do
|
||||||
@mock_warden.expects(:authenticate?).with(:rememberable, :token_authenticatable, :scope => :user).returns(true)
|
@mock_warden.expects(:authenticate?).with(:rememberable, :scope => :user).returns(true)
|
||||||
@mock_warden.expects(:user).with(:user).returns(User.new)
|
@mock_warden.expects(:user).with(:user).returns(User.new)
|
||||||
@controller.expects(:redirect_to).with(root_path)
|
@controller.expects(:redirect_to).with(root_path)
|
||||||
@controller.send :require_no_authentication
|
@controller.send :require_no_authentication
|
||||||
@@ -71,7 +71,7 @@ class HelpersTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test 'require no authentication sets a flash message' do
|
test 'require no authentication sets a flash message' do
|
||||||
@mock_warden.expects(:authenticate?).with(:rememberable, :token_authenticatable, :scope => :user).returns(true)
|
@mock_warden.expects(:authenticate?).with(:rememberable, :scope => :user).returns(true)
|
||||||
@mock_warden.expects(:user).with(:user).returns(User.new)
|
@mock_warden.expects(:user).with(:user).returns(User.new)
|
||||||
@controller.expects(:redirect_to).with(root_path)
|
@controller.expects(:redirect_to).with(root_path)
|
||||||
@controller.send :require_no_authentication
|
@controller.send :require_no_authentication
|
||||||
|
|||||||
@@ -88,16 +88,6 @@ class HttpAuthenticationTest < ActionDispatch::IntegrationTest
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'sign in should authenticate with really long token' do
|
|
||||||
token = "token_containing_so_many_characters_that_the_base64_encoding_will_wrap"
|
|
||||||
user = create_user
|
|
||||||
user.update_attribute :authentication_token, token
|
|
||||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => "Basic #{Base64.encode64("#{token}:x")}"
|
|
||||||
assert_response :success
|
|
||||||
assert_match "<email>user@test.com</email>", response.body
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def sign_in_as_new_user_with_http(username="user@test.com", password="12345678")
|
def sign_in_as_new_user_with_http(username="user@test.com", password="12345678")
|
||||||
|
|||||||
@@ -1,205 +0,0 @@
|
|||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class TokenAuthenticationTest < ActionDispatch::IntegrationTest
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and value through params' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token do
|
|
||||||
sign_in_as_new_user_with_token
|
|
||||||
|
|
||||||
assert_response :success
|
|
||||||
assert_current_url "/users?secret_token=#{VALID_AUTHENTICATION_TOKEN}"
|
|
||||||
assert_contain 'Welcome'
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and value through params, when params with the same key as scope exist' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token do
|
|
||||||
user = create_user_with_authentication_token
|
|
||||||
post exhibit_user_path(user), Devise.token_authentication_key => user.authentication_token, :user => { :some => "data" }
|
|
||||||
|
|
||||||
assert_response :success
|
|
||||||
assert_contain 'User is authenticated'
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key but does not store if stateless' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :skip_session_storage => [:token_auth] do
|
|
||||||
sign_in_as_new_user_with_token
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
|
|
||||||
get users_path
|
|
||||||
assert_redirected_to new_user_session_path
|
|
||||||
assert_not warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and value through http' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token do
|
|
||||||
sign_in_as_new_user_with_token(:http_auth => true)
|
|
||||||
|
|
||||||
assert_response :success
|
|
||||||
assert_match '<email>user@test.com</email>', response.body
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'does authenticate with valid authentication token key and value through params if not configured' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :params_authenticatable => [:database] do
|
|
||||||
sign_in_as_new_user_with_token
|
|
||||||
|
|
||||||
assert_contain 'You need to sign in or sign up before continuing'
|
|
||||||
assert_contain 'Sign in'
|
|
||||||
assert_not warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'does authenticate with valid authentication token key and value through http if not configured' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :http_authenticatable => [:database] do
|
|
||||||
sign_in_as_new_user_with_token(:http_auth => true)
|
|
||||||
|
|
||||||
assert_response 401
|
|
||||||
assert_contain 'Invalid email or password.'
|
|
||||||
assert_not warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'does not authenticate with improper authentication token key' do
|
|
||||||
swap Devise, :token_authentication_key => :donald_duck_token do
|
|
||||||
sign_in_as_new_user_with_token(:auth_token_key => :secret_token)
|
|
||||||
assert_equal new_user_session_path, @request.path
|
|
||||||
|
|
||||||
assert_contain 'You need to sign in or sign up before continuing'
|
|
||||||
assert_contain 'Sign in'
|
|
||||||
assert_not warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'does not authenticate with improper authentication token value' do
|
|
||||||
store_translations :en, :devise => {:failure => {:invalid_token => 'LOL, that was not a single character correct.'}} do
|
|
||||||
sign_in_as_new_user_with_token(:auth_token => '*** INVALID TOKEN ***')
|
|
||||||
assert_equal new_user_session_path, @request.path
|
|
||||||
|
|
||||||
assert_contain 'LOL, that was not a single character correct.'
|
|
||||||
assert_contain 'Sign in'
|
|
||||||
assert_not warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and do not store if stateless and timeoutable are enabled' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :skip_session_storage => [:token_auth], :timeout_in => (0.1).second do
|
|
||||||
user = sign_in_as_new_user_with_token
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
|
|
||||||
# Expiring does not work because we are setting the session value when accessing it
|
|
||||||
sleep 0.3
|
|
||||||
|
|
||||||
get_users_path_as_existing_user(user)
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should reset token and not authenticate when expire_auth_token_on_timeout is set to true, timeoutable is enabled and we have a timed out session' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :expire_auth_token_on_timeout => true, :timeout_in => (-1).minute do
|
|
||||||
user = sign_in_as_new_user_with_token
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
token = user.authentication_token
|
|
||||||
|
|
||||||
get_users_path_as_existing_user(user)
|
|
||||||
assert_not warden.authenticated?(:user)
|
|
||||||
user.reload
|
|
||||||
assert_not_equal token, user.authentication_token
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should not be subject to injection' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token do
|
|
||||||
user1 = create_user_with_authentication_token()
|
|
||||||
|
|
||||||
# Clean up user cache
|
|
||||||
@user = nil
|
|
||||||
|
|
||||||
user2 = create_user_with_authentication_token(:email => "another@test.com")
|
|
||||||
user2.update_attribute(:authentication_token, "ANOTHERTOKEN")
|
|
||||||
|
|
||||||
assert_not_equal user1, user2
|
|
||||||
visit users_path(Devise.token_authentication_key.to_s + '[$ne]' => user1.authentication_token)
|
|
||||||
assert_nil warden.user(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and value through http header' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token do
|
|
||||||
sign_in_as_new_user_with_token(:token_auth => true)
|
|
||||||
|
|
||||||
assert_response :success
|
|
||||||
assert_match '<email>user@test.com</email>', response.body
|
|
||||||
assert_equal request.env['devise.token_options'], {}
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and value through http header, with options' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :http_authenticatable => [:token_options] do
|
|
||||||
signature = "**TESTSIGNATURE**"
|
|
||||||
sign_in_as_new_user_with_token(:token_auth => true, :token_options => {:signature => signature, :nonce => 'def'})
|
|
||||||
|
|
||||||
assert_response :success
|
|
||||||
assert_match '<email>user@test.com</email>', response.body
|
|
||||||
assert_equal request.env['devise.token_options'][:signature], signature
|
|
||||||
assert_equal request.env['devise.token_options'][:nonce], 'def'
|
|
||||||
assert warden.authenticated?(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'authenticate with valid authentication token key and value through http header without allowing token authorization setting is denied' do
|
|
||||||
swap Devise, :token_authentication_key => :secret_token, :http_authenticatable => false do
|
|
||||||
sign_in_as_new_user_with_token(:token_auth => true)
|
|
||||||
|
|
||||||
assert_response :unauthorized
|
|
||||||
assert_nil warden.user(:user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'does not authenticate with improper authentication token value in header' do
|
|
||||||
sign_in_as_new_user_with_token(:token_auth => true, :auth_token => '*** INVALID TOKEN ***')
|
|
||||||
|
|
||||||
assert_response :unauthorized
|
|
||||||
assert_nil warden.user(:user)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def sign_in_as_new_user_with_token(options = {})
|
|
||||||
user = options.delete(:user) || create_user_with_authentication_token(options)
|
|
||||||
|
|
||||||
options[:auth_token_key] ||= Devise.token_authentication_key
|
|
||||||
options[:auth_token] ||= user.authentication_token
|
|
||||||
|
|
||||||
if options[:http_auth]
|
|
||||||
header = "Basic #{Base64.encode64("#{VALID_AUTHENTICATION_TOKEN}:X")}"
|
|
||||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => header
|
|
||||||
elsif options[:token_auth]
|
|
||||||
token_options = options[:token_options] || {}
|
|
||||||
header = ActionController::HttpAuthentication::Token.encode_credentials(options[:auth_token], token_options)
|
|
||||||
get users_path(:format => :xml), {}, "HTTP_AUTHORIZATION" => header
|
|
||||||
else
|
|
||||||
visit users_path(options[:auth_token_key].to_sym => options[:auth_token])
|
|
||||||
end
|
|
||||||
|
|
||||||
user
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_user_with_authentication_token(options={})
|
|
||||||
user = create_user(options)
|
|
||||||
user.authentication_token = VALID_AUTHENTICATION_TOKEN
|
|
||||||
user.save
|
|
||||||
user
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_users_path_as_existing_user(user)
|
|
||||||
sign_in_as_new_user_with_token(:user => user)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@@ -50,12 +50,12 @@ class MappingTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test 'has strategies depending on the model declaration' do
|
test 'has strategies depending on the model declaration' do
|
||||||
assert_equal [:rememberable, :token_authenticatable, :database_authenticatable], Devise.mappings[:user].strategies
|
assert_equal [:rememberable, :database_authenticatable], Devise.mappings[:user].strategies
|
||||||
assert_equal [:database_authenticatable], Devise.mappings[:admin].strategies
|
assert_equal [:database_authenticatable], Devise.mappings[:admin].strategies
|
||||||
end
|
end
|
||||||
|
|
||||||
test 'has no input strategies depending on the model declaration' do
|
test 'has no input strategies depending on the model declaration' do
|
||||||
assert_equal [:rememberable, :token_authenticatable], Devise.mappings[:user].no_input_strategies
|
assert_equal [:rememberable], Devise.mappings[:user].no_input_strategies
|
||||||
assert_equal [], Devise.mappings[:admin].no_input_strategies
|
assert_equal [], Devise.mappings[:admin].no_input_strategies
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class TokenAuthenticatableTest < ActiveSupport::TestCase
|
|
||||||
|
|
||||||
test 'should reset authentication token' do
|
|
||||||
user = new_user
|
|
||||||
user.reset_authentication_token
|
|
||||||
previous_token = user.authentication_token
|
|
||||||
user.reset_authentication_token
|
|
||||||
assert_not_equal previous_token, user.authentication_token
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should ensure authentication token' do
|
|
||||||
user = new_user
|
|
||||||
user.ensure_authentication_token
|
|
||||||
previous_token = user.authentication_token
|
|
||||||
user.ensure_authentication_token
|
|
||||||
assert_equal previous_token, user.authentication_token
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should authenticate a valid user with authentication token and return it' do
|
|
||||||
user = create_user
|
|
||||||
user.ensure_authentication_token!
|
|
||||||
user.confirm!
|
|
||||||
authenticated_user = User.find_for_token_authentication(:auth_token => user.authentication_token)
|
|
||||||
assert_equal authenticated_user, user
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should return nil when authenticating an invalid user by authentication token' do
|
|
||||||
user = create_user
|
|
||||||
user.ensure_authentication_token!
|
|
||||||
user.confirm!
|
|
||||||
authenticated_user = User.find_for_token_authentication(:auth_token => user.authentication_token.reverse)
|
|
||||||
assert_nil authenticated_user
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'should not be subject to injection' do
|
|
||||||
user1 = create_user
|
|
||||||
user1.ensure_authentication_token!
|
|
||||||
user1.confirm!
|
|
||||||
|
|
||||||
user2 = create_user
|
|
||||||
user2.ensure_authentication_token!
|
|
||||||
user2.confirm!
|
|
||||||
|
|
||||||
user = User.find_for_token_authentication(:auth_token => {'$ne' => user1.authentication_token})
|
|
||||||
assert_nil user
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'required_fields should contain the fields that Devise uses' do
|
|
||||||
assert_same_content Devise::Models::TokenAuthenticatable.required_fields(User), [
|
|
||||||
:authentication_token
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -36,7 +36,4 @@ class User
|
|||||||
field :failed_attempts, :type => Integer, :default => 0 # Only if lock strategy is :failed_attempts
|
field :failed_attempts, :type => Integer, :default => 0 # Only if lock strategy is :failed_attempts
|
||||||
field :unlock_token, :type => String # Only if unlock strategy is :email or :both
|
field :unlock_token, :type => String # Only if unlock strategy is :email or :both
|
||||||
field :locked_at, :type => Time
|
field :locked_at, :type => Time
|
||||||
|
|
||||||
## Token authenticatable
|
|
||||||
field :authentication_token, :type => String
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ class CreateTables < ActiveRecord::Migration
|
|||||||
t.string :unlock_token # Only if unlock strategy is :email or :both
|
t.string :unlock_token # Only if unlock strategy is :email or :both
|
||||||
t.datetime :locked_at
|
t.datetime :locked_at
|
||||||
|
|
||||||
## Token authenticatable
|
|
||||||
t.string :authentication_token
|
|
||||||
|
|
||||||
t.timestamps
|
t.timestamps
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ ActiveRecord::Schema.define(:version => 20100401102949) do
|
|||||||
t.integer "failed_attempts", :default => 0
|
t.integer "failed_attempts", :default => 0
|
||||||
t.string "unlock_token"
|
t.string "unlock_token"
|
||||||
t.datetime "locked_at"
|
t.datetime "locked_at"
|
||||||
t.string "authentication_token"
|
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module SharedUser
|
|||||||
|
|
||||||
included do
|
included do
|
||||||
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
|
devise :database_authenticatable, :confirmable, :lockable, :recoverable,
|
||||||
:registerable, :rememberable, :timeoutable, :token_authenticatable,
|
:registerable, :rememberable, :timeoutable,
|
||||||
:trackable, :validatable, :omniauthable
|
:trackable, :validatable, :omniauthable
|
||||||
|
|
||||||
attr_accessor :other_key
|
attr_accessor :other_key
|
||||||
|
|||||||
Reference in New Issue
Block a user