Skip to content

Commit

Permalink
FEATURE: require admins to re-validate their email addresses if they …
Browse files Browse the repository at this point in the history
…haven't been seen for a number of days, configurable with the invalidate_inactive_admin_email_after_days site setting. Social logins are also revoked. Default is 365 days.
  • Loading branch information
nlalonde committed Dec 12, 2018
1 parent 7cac04e commit a1db15f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 0 deletions.
25 changes: 25 additions & 0 deletions app/jobs/scheduled/invalidate_inactive_admins.rb
@@ -0,0 +1,25 @@
module Jobs

class InvalidateInactiveAdmins < Jobs::Scheduled
every 1.day

def execute(_)
return if SiteSetting.invalidate_inactive_admin_email_after_days == 0

User.human_users
.where(admin: true)
.where('last_seen_at < ?', SiteSetting.invalidate_inactive_admin_email_after_days.days.ago)
.each do |user|

user.email_tokens.update_all(confirmed: false, expired: true)

Discourse.authenticators.each do |authenticator|
if authenticator.can_revoke? && authenticator.description_for_user(user).present?
authenticator.revoke(user)
end
end
end
end
end

end
1 change: 1 addition & 0 deletions config/locales/server.en.yml
Expand Up @@ -1299,6 +1299,7 @@ en:
content_security_policy_report_only: EXPERIMENTAL - Turn on Content-Security-Policy-Report-Only
content_security_policy_collect_reports: Enable CSP violation report collection at /csp_reports
content_security_policy_script_src: Additional whitelisted script sources. The current host and CDN are included by default.
invalidate_inactive_admin_email_after_days: "Admin accounts that have not visited the site in this number of days will need to re-validate their email address before logging in. Set to 0 to disable."
top_menu: "Determine which items appear in the homepage navigation, and in what order. Example latest|new|unread|categories|top|read|posted|bookmarks"
post_menu: "Determine which items appear on the post menu, and in what order. Example like|edit|flag|delete|share|bookmark|reply"
post_menu_hidden_items: "The menu items to hide by default in the post menu unless an expansion ellipsis is clicked on."
Expand Down
4 changes: 4 additions & 0 deletions config/site_settings.yml
Expand Up @@ -1260,6 +1260,10 @@ security:
content_security_policy_script_src:
type: list
default: ''
invalidate_inactive_admin_email_after_days:
default: 365
min: 0
max: 2000

onebox:
enable_flash_video_onebox: false
Expand Down
69 changes: 69 additions & 0 deletions spec/jobs/invalidate_inactive_admins_spec.rb
@@ -0,0 +1,69 @@
require 'rails_helper'

require_dependency 'jobs/scheduled/invalidate_inactive_admins'

describe Jobs::InvalidateInactiveAdmins do
let!(:active_admin) { Fabricate(:admin, last_seen_at: 1.hour.ago) }
before { active_admin.email_tokens.update_all(confirmed: true) }

subject { Jobs::InvalidateInactiveAdmins.new.execute({}) }

it "does nothing when all admins have been seen recently" do
SiteSetting.invalidate_inactive_admin_email_after_days = 365
subject
expect(active_admin.active).to eq(true)
expect(active_admin.email_tokens.where(confirmed: true).exists?).to eq(true)
end

context "with an admin who hasn't been seen recently" do
let!(:not_seen_admin) { Fabricate(:admin, last_seen_at: 370.days.ago) }
before { not_seen_admin.email_tokens.update_all(confirmed: true) }

context 'invalidate_inactive_admin_email_after_days = 365' do
before do
SiteSetting.invalidate_inactive_admin_email_after_days = 365
end

it 'marks email tokens as unconfirmed and keeps user as active' do
subject
expect(not_seen_admin.email_tokens.where(confirmed: true).exists?).to eq(false)
end

it 'keeps the user active' do
subject
expect(not_seen_admin.active).to eq(true)
end

context 'with social logins' do
before do
GithubUserInfo.create!(user_id: not_seen_admin.id, screen_name: 'bob', github_user_id: 100)
InstagramUserInfo.create!(user_id: not_seen_admin.id, screen_name: 'bob', instagram_user_id: 'examplel123123')
UserOpenId.create!(url: 'https://me.yahoo.com/id/123' , user_id: not_seen_admin.id, email: 'bob@example.com', active: true)
GoogleUserInfo.create!(user_id: not_seen_admin.id, google_user_id: 100, email: 'bob@example.com')
end

it 'removes the social logins' do
subject
expect(GithubUserInfo.where(user_id: not_seen_admin.id).exists?).to eq(false)
expect(InstagramUserInfo.where(user_id: not_seen_admin.id).exists?).to eq(false)
expect(GoogleUserInfo.where(user_id: not_seen_admin.id).exists?).to eq(false)
expect(UserOpenId.where(user_id: not_seen_admin.id).exists?).to eq(false)
end
end
end

context 'invalidate_inactive_admin_email_after_days = 0 to disable this feature' do
before do
SiteSetting.invalidate_inactive_admin_email_after_days = 0
end

it 'does nothing' do
subject
expect(active_admin.active).to eq(true)
expect(active_admin.email_tokens.where(confirmed: true).exists?).to eq(true)
expect(not_seen_admin.active).to eq(true)
expect(not_seen_admin.email_tokens.where(confirmed: true).exists?).to eq(true)
end
end
end
end

4 comments on commit a1db15f

@SamSaffron
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't feel this is quite strong enough. Why not update the admin as active = false? This change only means they will need to re-connect social logins, they will still be able to login using username/password without email confirmation as far as I can tell.

@coding-horror
Copy link
Contributor

@coding-horror coding-horror commented on a1db15f Dec 12, 2018 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SamSaffron
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@discoursereviewbot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neil Lalonde posted:

What other bit?

[quote="SamSaffron, post:3, topic:723"]
they will still be able to login using username/password without email confirmation as far as I can tell.
[/quote]

That's not the case in my testing. The behaviour is identical to deactivating. (Both cases show the same modal as if you had signed up but not clicked the activation link yet, which is not great.)

Please sign in to comment.