diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index bb47e2a8bf7442f2a416ef0c6b0848db311af991..bf6be3d516b36c28b8666dee6fe4d7b9f4a15f7e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -12,7 +12,6 @@ class ApplicationController < ActionController::Base
   before_action :authenticate_user_from_private_token!
   before_action :authenticate_user!
   before_action :validate_user_service_ticket!
-  before_action :reject_blocked!
   before_action :check_password_expiration
   before_action :check_2fa_requirement
   before_action :ldap_security_check
@@ -87,22 +86,8 @@ class ApplicationController < ActionController::Base
     logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
   end
 
-  def reject_blocked!
-    if current_user && current_user.blocked?
-      sign_out current_user
-      flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
-      redirect_to new_user_session_path
-    end
-  end
-
   def after_sign_in_path_for(resource)
-    if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
-      sign_out resource
-      flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
-      new_user_session_path
-    else
-      stored_location_for(:redirect) || stored_location_for(resource) || root_path
-    end
+    stored_location_for(:redirect) || stored_location_for(resource) || root_path
   end
 
   def after_sign_out_path_for(resource)
diff --git a/app/controllers/explore/application_controller.rb b/app/controllers/explore/application_controller.rb
index a1ab8b99048fc4d5979b1a7064a999d0d2a301fa..baf54520b9c5c208cf7710c40052e196b732436f 100644
--- a/app/controllers/explore/application_controller.rb
+++ b/app/controllers/explore/application_controller.rb
@@ -1,5 +1,5 @@
 class Explore::ApplicationController < ApplicationController
-  skip_before_action :authenticate_user!, :reject_blocked!
+  skip_before_action :authenticate_user!
 
   layout 'explore'
 end
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index 37feff79999561954faf962405280fa7488b9dd6..87c0f8905ff7a8607b6a2e03c60b0363cb5d56e0 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -1,5 +1,5 @@
 class HelpController < ApplicationController
-  skip_before_action :authenticate_user!, :reject_blocked!
+  skip_before_action :authenticate_user!
 
   layout 'help'
 
diff --git a/app/controllers/koding_controller.rb b/app/controllers/koding_controller.rb
index f3759b4c0ea2b77696e0342d5186b703288fc455..6b1e64ce8194db812bced74c816d40e34889cdcf 100644
--- a/app/controllers/koding_controller.rb
+++ b/app/controllers/koding_controller.rb
@@ -1,5 +1,5 @@
 class KodingController < ApplicationController
-  before_action :check_integration!, :authenticate_user!, :reject_blocked!
+  before_action :check_integration!
   layout 'koding'
 
   def index
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 50ba33ed57033d2a57f3704b020d16d98865ef74..61686499bd3d38c16c512a0280a3129b5606f0af 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -1,6 +1,6 @@
 class Projects::UploadsController < Projects::ApplicationController
-  skip_before_action :reject_blocked!, :project,
-    :repository, if: -> { action_name == 'show' && image_or_video? }
+  skip_before_action :project, :repository,
+    if: -> { action_name == 'show' && image_or_video? }
 
   before_action :authorize_upload_file!, only: [:create]
 
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 6576ebd5235a67d8bfa2d7af4dc60d5b02454c95..612d69cf557a1dc0fc61b1805a923453e7b53393 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,5 +1,5 @@
 class SearchController < ApplicationController
-  skip_before_action :authenticate_user!, :reject_blocked!
+  skip_before_action :authenticate_user!
 
   include SearchHelper
 
diff --git a/app/models/user.rb b/app/models/user.rb
index 33666b4f35bd4ad6122cb6269371db8239f325a4..f9245cdb82a8edd6f3e417fe7a1fb323877692f6 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -167,6 +167,15 @@ class User < ActiveRecord::Base
       def blocked?
         true
       end
+
+      def active_for_authentication?
+        false
+      end
+
+      def inactive_message
+        "Your account has been blocked. Please contact your GitLab " \
+          "administrator if you think this is an error."
+      end
     end
   end
 
diff --git a/changelogs/unreleased/rs-warden-blocked-users.yml b/changelogs/unreleased/rs-warden-blocked-users.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c0c23fb6f112b1560c98a5b252f95572fa27bacc
--- /dev/null
+++ b/changelogs/unreleased/rs-warden-blocked-users.yml
@@ -0,0 +1,4 @@
+---
+title: Don't perform Devise trackable updates on blocked User records
+merge_request: 8915
+author:
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index f1c8891e87ab9a833adbb8691b1109c2a792c750..0347e789576ec81ce940912ecdfa73895bf5dbc4 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -170,68 +170,24 @@ describe Projects::UploadsController do
             project.team << [user, :master]
           end
 
-          context "when the user is blocked" do
+          context "when the file exists" do
             before do
-              user.block
-              project.team << [user, :master]
-            end
-
-            context "when the file exists" do
-              before do
-                allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
-                allow(jpg).to receive(:exists?).and_return(true)
-              end
-
-              context "when the file is an image" do
-                before do
-                  allow_any_instance_of(FileUploader).to receive(:image?).and_return(true)
-                end
-
-                it "responds with status 200" do
-                  go
-
-                  expect(response).to have_http_status(200)
-                end
-              end
-
-              context "when the file is not an image" do
-                it "redirects to the sign in page" do
-                  go
-
-                  expect(response).to redirect_to(new_user_session_path)
-                end
-              end
+              allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
+              allow(jpg).to receive(:exists?).and_return(true)
             end
 
-            context "when the file doesn't exist" do
-              it "redirects to the sign in page" do
-                go
+            it "responds with status 200" do
+              go
 
-                expect(response).to redirect_to(new_user_session_path)
-              end
+              expect(response).to have_http_status(200)
             end
           end
 
-          context "when the user isn't blocked" do
-            context "when the file exists" do
-              before do
-                allow_any_instance_of(FileUploader).to receive(:file).and_return(jpg)
-                allow(jpg).to receive(:exists?).and_return(true)
-              end
-
-              it "responds with status 200" do
-                go
-
-                expect(response).to have_http_status(200)
-              end
-            end
-
-            context "when the file doesn't exist" do
-              it "responds with status 404" do
-                go
+          context "when the file doesn't exist" do
+            it "responds with status 404" do
+              go
 
-                expect(response).to have_http_status(404)
-              end
+              expect(response).to have_http_status(404)
             end
           end
         end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index c6f7869516e207f03a22a094660e3894eacbe45e..1732b1a00817e385c19c9a5bcd1f683fc99cc085 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -14,6 +14,14 @@ FactoryGirl.define do
       admin true
     end
 
+    trait :blocked do
+      after(:build) { |user, _| user.block! }
+    end
+
+    trait :external do
+      external true
+    end
+
     trait :two_factor do
       two_factor_via_otp
     end
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index ab7d89306db893cd9a4653926e5ff82e14963d3c..ae609160e18ca8b0bad7cf3b4a838b13f29e600e 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -32,6 +32,22 @@ feature 'Login', feature: true do
     end
   end
 
+  describe 'with a blocked account' do
+    it 'prevents the user from logging in' do
+      user = create(:user, :blocked)
+
+      login_with(user)
+
+      expect(page).to have_content('Your account has been blocked.')
+    end
+
+    it 'does not update Devise trackable attributes' do
+      user = create(:user, :blocked)
+
+      expect { login_with(user) }.not_to change { user.reload.sign_in_count }
+    end
+  end
+
   describe 'with two-factor authentication' do
     def enter_code(code)
       fill_in 'user_otp_attempt', with: code