Skip to content
Permalink
Browse files

Warn on suspicious login, after long period of inactivity

  • Loading branch information...
kevinrobinson committed Mar 6, 2019
1 parent a8eff2f commit 24122f1eb840a0e7c1b6d0d5354ef8329c32aeb7
@@ -60,9 +60,9 @@ def authenticate_without_consistent_timing!
ldap_login = PerDistrict.new.ldap_login_for_educator(educator)
return fail!(:invalid) unless is_authorized_by_ldap?(ldap_login, password_text)

# Success, run password checks and store results encrypted and noised,
# ignoring any errors in the process.
# Success, run security checks
store_password_check(password_text)
warn_if_suspicious(educator)

# Return success
return success!(educator)
@@ -106,6 +106,10 @@ def store_password_check(password_text)
nil
end

def warn_if_suspicious(educator)
LoginChecker.new(educator).warn_if_suspicious
end

def logger
Rails.logger
end
@@ -0,0 +1,29 @@
# Check for suspicious bits about the login, for warning.
class LoginChecker
def initialize(educator, options = {})
@educator = educator
@time_now = options.fetch(:time_now, Time.now)
end

def warn_if_suspicious
flags = infer_flags
warn_about(flags)
flags
end

private
def infer_flags
last_login_at = LoginActivity.last_login_at(@educator)

flags = []
flags << :first_login_month_after_creation if last_login_at.nil? && @educator.created_at < (@time_now - 30.days)
flags << :first_login_after_year if last_login_at.present? && last_login_at < (@time_now - 1.year)
flags.sort
end

def warn_about(flags)
if flags.size > 0
Rollbar.warn('LoginChecker#warn_if_suspicious', flags: flags)
end
end
end
@@ -14,4 +14,13 @@ class LoginActivity < ApplicationRecord
belongs_to :user,
polymorphic: true,
optional: true

# Return ActiveSupport::TimeWithZone or nil
def self.last_login_at(educator_id)
LoginActivity.where(user_id: educator_id)
.order(created_at: :desc)
.limit(1)
.first
.try(:created_at)
end
end
@@ -0,0 +1,26 @@
require 'spec_helper'

RSpec.describe LoginChecker do
let!(:pals) { TestPals.create! }

it '#warn_if_suspicious reports to Rollbar on :first_login_after_year' do
LoginActivity.create!({
user_id: pals.healey_vivian_teacher.id,
created_at: pals.time_now - 2.years
})

allow(Rollbar).to receive(:warn)
expect(Rollbar).to receive(:warn).once.with('LoginChecker#warn_if_suspicious', flags: [:first_login_after_year])
checker = LoginChecker.new(pals.healey_vivian_teacher, time_now: pals.time_now)
expect(checker.warn_if_suspicious).to eq [:first_login_after_year]
end

it '#warn_if_suspicious reports to Rollbar on :first_login_month_after_creation' do
pals.healey_vivian_teacher.update!(created_at: pals.time_now - 32.days)

allow(Rollbar).to receive(:warn)
expect(Rollbar).to receive(:warn).once.with('LoginChecker#warn_if_suspicious', flags: [:first_login_month_after_creation])
checker = LoginChecker.new(pals.healey_vivian_teacher, time_now: pals.time_now)
expect(checker.warn_if_suspicious).to eq [:first_login_month_after_creation]
end
end

0 comments on commit 24122f1

Please sign in to comment.
You can’t perform that action at this time.