mirror of
https://github.com/heartcombo/devise.git
synced 2026-01-09 23:08:05 -05:00
Introducing timeoutable to timeout sessions without activity.
This commit is contained in:
@@ -34,6 +34,9 @@ Devise.setup do |config|
|
||||
# The time the user will be remembered without asking for credentials again.
|
||||
# config.remember_for = 2.weeks
|
||||
|
||||
# The time interval to timeout the user session without activity.
|
||||
# config.timeout = 10.minutes
|
||||
|
||||
# Configure the e-mail address which will be shown in DeviseMailer.
|
||||
# config.mailer_sender = "foo.bar@yourapp.com"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module Devise
|
||||
ALL = [:authenticatable, :confirmable, :recoverable, :rememberable, :validatable].freeze
|
||||
ALL = [:authenticatable, :confirmable, :recoverable, :rememberable, :timeoutable, :validatable].freeze
|
||||
|
||||
# Maps controller names to devise modules
|
||||
CONTROLLERS = {
|
||||
@@ -45,6 +45,10 @@ module Devise
|
||||
mattr_accessor :confirm_within
|
||||
@@confirm_within = 0.days
|
||||
|
||||
# Time interval to timeout the user session without activity.
|
||||
mattr_accessor :timeout
|
||||
@@timeout = 10.minutes
|
||||
|
||||
# Used to define the password encryption algorithm.
|
||||
mattr_accessor :encryptor
|
||||
@@encryptor = :sha1
|
||||
@@ -141,5 +145,4 @@ Warden::Manager.default_scope = nil
|
||||
|
||||
require 'devise/strategies/base'
|
||||
require 'devise/serializers/base'
|
||||
|
||||
require 'devise/rails'
|
||||
|
||||
@@ -6,7 +6,6 @@ Warden::Manager.after_set_user do |record, warden, options|
|
||||
if record && record.respond_to?(:active?) && !record.active?
|
||||
scope = options[:scope]
|
||||
warden.logout(scope)
|
||||
|
||||
if warden.winning_strategy
|
||||
# If winning strategy was set, this is being called after authenticate and
|
||||
# there is no need to force a redirect.
|
||||
|
||||
17
lib/devise/hooks/timeoutable.rb
Normal file
17
lib/devise/hooks/timeoutable.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
Warden::Manager.after_set_user do |record, warden, options|
|
||||
if record.present?
|
||||
scope = options[:scope]
|
||||
# Current record may have already be logged out by another hook.
|
||||
# For instance, Devise confirmable hook may have logged the record out.
|
||||
# TODO: move this verify to warden: he should stop the hooks if the record
|
||||
# is logged out by any of them.
|
||||
if warden.authenticated?(scope)
|
||||
last_request_at = warden.session(scope)['last_request_at']
|
||||
if last_request_at && last_request_at <= 10.minutes.ago.utc
|
||||
warden.logout(scope)
|
||||
throw :warden, :scope => scope, :message => :timeout
|
||||
end
|
||||
warden.session(scope)['last_request_at'] = Time.now.utc
|
||||
end
|
||||
end
|
||||
end
|
||||
21
lib/devise/models/timeoutable.rb
Normal file
21
lib/devise/models/timeoutable.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
require 'devise/hooks/timeoutable'
|
||||
|
||||
module Devise
|
||||
module Models
|
||||
|
||||
# Timeoutable
|
||||
module Timeoutable
|
||||
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
extend ClassMethods
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
end
|
||||
|
||||
Devise::Models.config(self, :timeout)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
require 'test/test_helper'
|
||||
require 'ostruct'
|
||||
require 'ostruct'
|
||||
|
||||
class FailureTest < ActiveSupport::TestCase
|
||||
|
||||
@@ -22,6 +22,18 @@ class FailureTest < ActiveSupport::TestCase
|
||||
assert_equal '/users/sign_in?test=true', location
|
||||
end
|
||||
|
||||
test 'uses the given message' do
|
||||
warden = OpenStruct.new(:message => 'Hello world')
|
||||
location = call_failure('warden' => warden).second['Location']
|
||||
assert_equal '/users/sign_in?message=Hello+world', location
|
||||
end
|
||||
|
||||
test 'setup default url' do
|
||||
Devise::FailureApp.default_url = 'test/sign_in'
|
||||
location = call_failure('warden.options' => { :scope => nil }).second['Location']
|
||||
assert_equal '/test/sign_in?unauthenticated=true', location
|
||||
end
|
||||
|
||||
test 'set content type to default text/plain' do
|
||||
assert_equal 'text/plain', call_failure.second['Content-Type']
|
||||
end
|
||||
|
||||
@@ -58,9 +58,9 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'not confirmed user and setup to block without confirmation should not be able to sign in' do
|
||||
test 'not confirmed user with setup to block without confirmation should not be able to sign in' do
|
||||
Devise.confirm_within = 0
|
||||
user = sign_in_as_user(:confirm => false)
|
||||
sign_in_as_user(:confirm => false)
|
||||
|
||||
assert_contain 'You have to confirm your account before continuing'
|
||||
assert_not warden.authenticated?(:user)
|
||||
@@ -68,7 +68,7 @@ class ConfirmationTest < ActionController::IntegrationTest
|
||||
|
||||
test 'not confirmed user but configured with some days to confirm should be able to sign in' do
|
||||
Devise.confirm_within = 1
|
||||
user = sign_in_as_user(:confirm => false)
|
||||
sign_in_as_user(:confirm => false)
|
||||
|
||||
assert_response :success
|
||||
assert warden.authenticated?(:user)
|
||||
|
||||
44
test/integration/timeoutable_test.rb
Normal file
44
test/integration/timeoutable_test.rb
Normal file
@@ -0,0 +1,44 @@
|
||||
require 'test/test_helper'
|
||||
|
||||
class SessionTimeoutTest < ActionController::IntegrationTest
|
||||
|
||||
def last_request_at
|
||||
@controller.user_session['last_request_at']
|
||||
end
|
||||
|
||||
test 'set last request at in user session after each request' do
|
||||
sign_in_as_user
|
||||
old_last_request = last_request_at
|
||||
assert_not_nil last_request_at
|
||||
get users_path
|
||||
assert_not_nil last_request_at
|
||||
assert_not_equal old_last_request, last_request_at
|
||||
end
|
||||
|
||||
test 'time out user session after default limit time' do
|
||||
sign_in_as_user
|
||||
assert_response :success
|
||||
assert warden.authenticated?(:user)
|
||||
|
||||
# Setup last_request_at to timeout
|
||||
get new_user_path
|
||||
assert_not_nil last_request_at
|
||||
|
||||
get users_path
|
||||
assert_redirected_to new_user_session_path(:timeout => true)
|
||||
assert_not warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
test 'not time out user session before default limit time' do
|
||||
user = sign_in_as_user
|
||||
|
||||
# Setup last_request_at to timeout
|
||||
get edit_user_path(user)
|
||||
assert_not_nil last_request_at
|
||||
|
||||
get users_path
|
||||
assert_response :success
|
||||
assert warden.authenticated?(:user)
|
||||
end
|
||||
|
||||
end
|
||||
5
test/models/timeoutable_test.rb
Normal file
5
test/models/timeoutable_test.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
require 'test/test_helper'
|
||||
|
||||
class TimeoutableTest < ActiveSupport::TestCase
|
||||
|
||||
end
|
||||
@@ -16,6 +16,10 @@ class Rememberable < User
|
||||
devise :authenticatable, :rememberable
|
||||
end
|
||||
|
||||
class Timeoutable < User
|
||||
devise :timeoutable
|
||||
end
|
||||
|
||||
class Validatable < User
|
||||
devise :authenticatable, :validatable
|
||||
end
|
||||
@@ -32,7 +36,8 @@ class Configurable < User
|
||||
devise :all, :stretches => 15,
|
||||
:pepper => 'abcdef',
|
||||
:confirm_within => 5.days,
|
||||
:remember_for => 7.days
|
||||
:remember_for => 7.days,
|
||||
:timeout => 15.minutes
|
||||
end
|
||||
|
||||
class ActiveRecordTest < ActiveSupport::TestCase
|
||||
@@ -54,33 +59,38 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'include by default authenticatable only' do
|
||||
assert_include_modules Authenticable, :authenticatable
|
||||
assert_not_include_modules Authenticable, :confirmable, :recoverable, :rememberable, :validatable
|
||||
assert_include_modules Authenticatable, :authenticatable
|
||||
assert_not_include_modules Authenticatable, :confirmable, :recoverable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add confirmable module only' do
|
||||
assert_include_modules Confirmable, :authenticatable, :confirmable
|
||||
assert_not_include_modules Confirmable, :recoverable, :rememberable, :validatable
|
||||
assert_not_include_modules Confirmable, :recoverable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add recoverable module only' do
|
||||
assert_include_modules Recoverable, :authenticatable, :recoverable
|
||||
assert_not_include_modules Recoverable, :confirmable, :rememberable, :validatable
|
||||
assert_not_include_modules Recoverable, :confirmable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add rememberable module only' do
|
||||
assert_include_modules Rememberable, :authenticatable, :rememberable
|
||||
assert_not_include_modules Rememberable, :confirmable, :recoverable, :validatable
|
||||
assert_not_include_modules Rememberable, :confirmable, :recoverable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'add timeoutable module only' do
|
||||
assert_include_modules Timeoutable, :authenticatable, :timeoutable
|
||||
assert_not_include_modules Timeoutable, :confirmable, :recoverable, :rememberable, :validatable
|
||||
end
|
||||
|
||||
test 'add validatable module only' do
|
||||
assert_include_modules Validatable, :authenticatable, :validatable
|
||||
assert_not_include_modules Validatable, :confirmable, :recoverable, :rememberable
|
||||
assert_not_include_modules Validatable, :confirmable, :recoverable, :timeoutable, :rememberable
|
||||
end
|
||||
|
||||
test 'add all modules' do
|
||||
assert_include_modules Devisable,
|
||||
:authenticatable, :confirmable, :recoverable, :rememberable, :validatable
|
||||
:authenticatable, :confirmable, :recoverable, :rememberable, :timeoutable, :validatable
|
||||
end
|
||||
|
||||
test 'configure modules with except option' do
|
||||
@@ -104,6 +114,10 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
||||
assert_equal 7.days, Configurable.remember_for
|
||||
end
|
||||
|
||||
test 'set a default value for timeout' do
|
||||
assert_equal 15.minutes, Configurable.new.timeout
|
||||
end
|
||||
|
||||
test 'set null fields on migrations' do
|
||||
Admin.create!
|
||||
end
|
||||
|
||||
@@ -4,4 +4,14 @@ class UsersController < ApplicationController
|
||||
def index
|
||||
user_session[:cart] = "Cart"
|
||||
end
|
||||
|
||||
def new
|
||||
user_session['last_request_at'] = 11.minutes.ago.utc
|
||||
render :text => 'New user!'
|
||||
end
|
||||
|
||||
def edit
|
||||
user_session['last_request_at'] = 9.minutes.ago.utc
|
||||
render :text => 'Edit user!'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ ActionController::Routing::Routes.draw do |map|
|
||||
:path_prefix => '/:locale',
|
||||
:requirements => { :extra => 'value' }
|
||||
|
||||
map.resources :users, :only => :index
|
||||
map.resources :users, :only => [:index, :new, :edit]
|
||||
map.resources :admins, :only => :index
|
||||
map.root :controller => :home
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ end
|
||||
|
||||
Webrat.configure do |config|
|
||||
config.mode = :rails
|
||||
config.open_error_files = false
|
||||
end
|
||||
|
||||
class ActiveSupport::TestCase
|
||||
|
||||
Reference in New Issue
Block a user