Introducing timeoutable to timeout sessions without activity.

This commit is contained in:
Carlos Antonio da Silva
2009-11-22 22:19:29 -02:00
parent 966b48c414
commit 099c77e867
13 changed files with 145 additions and 16 deletions

View File

@@ -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"

View File

@@ -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'

View File

@@ -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.

View 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

View 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

View File

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

View File

@@ -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)

View 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

View File

@@ -0,0 +1,5 @@
require 'test/test_helper'
class TimeoutableTest < ActiveSupport::TestCase
end

View File

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

View File

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

View File

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

View File

@@ -33,6 +33,7 @@ end
Webrat.configure do |config|
config.mode = :rails
config.open_error_files = false
end
class ActiveSupport::TestCase