From afbb56be23c1ee2304ef3b55f13e764d5d129153 Mon Sep 17 00:00:00 2001 From: Sai Praveen Gudimetla Date: Fri, 12 Apr 2024 14:47:34 -0500 Subject: [PATCH] add admin autolock feature (#193) * add admin autolock feature * use devise-security-extension gem to support rails v3 * override devise security update_last_activity method to support mongoid * fix rspecs * fix another spec failure --- Gemfile | 2 ++ Gemfile.lock | 4 +++ app/models/user.rb | 19 +++++++++++- config/application.rb | 1 + config/initializers/devise.rb | 10 +++++++ spec/controllers/users_controller_spec.rb | 35 +++++++++++++++++++++++ 6 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 spec/controllers/users_controller_spec.rb diff --git a/Gemfile b/Gemfile index c04af4483..ce727dd5c 100644 --- a/Gemfile +++ b/Gemfile @@ -76,6 +76,8 @@ gem 'bootstrap-kaminari-views', '0.0.5' gem "pd_x12", "~> 1.5.4" gem 'carrierwave-mongoid', '0.7.1', :require => 'carrierwave/mongoid' gem 'devise', '3.3.0' +# for account locking +gem 'devise_security_extension' gem "rsec", "~> 0.4.2" gem "mongoid_auto_increment", '0.1.2' gem 'american_date', '1.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index a3ece45be..e9c3688d6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -144,6 +144,9 @@ GEM railties (>= 3.2.6, < 5) thread_safe (~> 0.1) warden (~> 1.2.3) + devise_security_extension (0.10.0) + devise (>= 3.0.0, < 4.0) + railties (>= 3.2.6, < 5.0) diff-lcs (1.2.5) docile (1.1.5) equalizer (0.0.11) @@ -416,6 +419,7 @@ DEPENDENCIES database_cleaner (= 1.5.3) designmodo-flatuipro-rails! devise (= 3.3.0) + devise_security_extension edi_codec! factory_girl (= 4.5.0) factory_girl_rails (= 4.5.0) diff --git a/app/models/user.rb b/app/models/user.rb index fbd7edd68..4ba44ab37 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,7 +6,9 @@ class User # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, - :recoverable, :rememberable, :trackable, :validatable, :registerable + :recoverable, :rememberable, :trackable, :validatable, :registerable, + :session_limitable, # Limit number of sessions + :expirable # Setup accessible (or protected) attributes for your model attr_accessible :email, :password, :password_confirmation, :remember_me, :approved, :role, :updated_by @@ -26,6 +28,13 @@ class User ## Rememberable field :remember_created_at, :type => Time + ## Session Limitable + field :unique_session_id, type: String + + ## Expirable + field :last_activity_at, type: Time + field :expired_at, type: Time + ## Trackable field :sign_in_count, :type => Integer, :default => 0 field :current_sign_in_at, :type => Time @@ -56,6 +65,14 @@ class User before_save :ensure_authentication_token + def update_last_activity! + if respond_to?(:update_column) + self.update_column(:last_activity_at, Time.now.utc) + elsif defined? Mongoid + self.update_attribute(:last_activity_at, Time.now.utc) + end + end + def update_attributes_as(update_params, current_user = nil) params = update_params.dup if current_user diff --git a/config/application.rb b/config/application.rb index ad88afa9c..ac59161cd 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,3 +1,4 @@ +DEVISE_ORM = :mongoid require File.expand_path('../boot', __FILE__) # Pick the frameworks you want: diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index c94f07baf..f451c9e36 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -251,4 +251,14 @@ # When using omniauth, Devise cannot automatically set Omniauth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' + + # ==> Configuration for :expirable + # Time period for account expiry from last_activity_at + user_account_lock_period = 60 + unless ENV['DEVISE_USER_INACTIVITY_LOCK_PERIOD_IN_DAYS'].blank? + period_in_days_env = ENV['DEVISE_USER_INACTIVITY_LOCK_PERIOD_IN_DAYS'] + num_days = period_in_days_env.to_i + user_account_lock_period = num_days if num_days.to_s == period_in_days_env + end + config.expire_after = user_account_lock_period.days end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb new file mode 100644 index 000000000..79afb4a5b --- /dev/null +++ b/spec/controllers/users_controller_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +describe UsersController, :dbclean => :after_each do + + describe 'GET index' do + context "attempting to log in an expired user" do + let(:user) do + user_record = FactoryGirl.create(:user, :admin) + user_record.last_activity_at = Time.now - 180.days + user_record.save! + user_record + end + + it "can't access the endpoint" do + sign_in user + get :index + expect(response).to redirect_to("http://test.host/accounts/sign_in") + end + end + + context "attempting to log in an valid user" do + let(:user) do + user_record = FactoryGirl.create(:user, :admin) + user_record.save! + user_record + end + + it "can't access the endpoint" do + sign_in user + get :index + expect(response).to render_template :index + end + end + end +end