diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 01e2e7b2f980c3f544f7e34cc977923666ef5cf3..e15d83631b38a0db6bb07121522bd06ce195a04c 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -13,6 +13,7 @@ class ApplicationController < ActionController::Base
   before_action :validate_user_service_ticket!
   before_action :reject_blocked!
   before_action :check_password_expiration
+  before_action :check_tfa_requirement
   before_action :ldap_security_check
   before_action :default_headers
   before_action :add_gon_variables
@@ -223,6 +224,13 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  def check_tfa_requirement
+    if two_factor_authentication_required? && current_user && !current_user.two_factor_enabled
+      redirect_to new_profile_two_factor_auth_path,
+                  alert: 'You must configure Two-Factor Authentication in your account'
+    end
+  end
+
   def ldap_security_check
     if current_user && current_user.requires_ldap_check?
       unless Gitlab::LDAP::Access.allowed?(current_user)
@@ -357,6 +365,10 @@ class ApplicationController < ActionController::Base
     current_application_settings.import_sources.include?('git')
   end
 
+  def two_factor_authentication_required?
+    current_application_settings.require_two_factor_authentication
+  end
+
   def redirect_to_home_page_url?
     # If user is not signed-in and tries to access root_path - redirect him to landing page
     # Don't redirect to the default URL to prevent endless redirections
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index e6b99be37fb7fab9bcf2190321a3df0e446b050f..05c84fb720e37f6375f90a7d27615604db453e80 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -1,4 +1,6 @@
 class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
+  skip_before_action :check_tfa_requirement
+
   def new
     unless current_user.otp_secret
       current_user.otp_secret = User.generate_otp_secret(32)
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 724429e755855737ed3c66b75f5224e8f2fa0425..7c107da116c862b86bf4a345a215939720831c57 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -2,32 +2,34 @@
 #
 # Table name: application_settings
 #
-#  id                           :integer          not null, primary key
-#  default_projects_limit       :integer
-#  signup_enabled               :boolean
-#  signin_enabled               :boolean
-#  gravatar_enabled             :boolean
-#  sign_in_text                 :text
-#  created_at                   :datetime
-#  updated_at                   :datetime
-#  home_page_url                :string(255)
-#  default_branch_protection    :integer          default(2)
-#  twitter_sharing_enabled      :boolean          default(TRUE)
-#  restricted_visibility_levels :text
-#  version_check_enabled        :boolean          default(TRUE)
-#  max_attachment_size          :integer          default(10), not null
-#  default_project_visibility   :integer
-#  default_snippet_visibility   :integer
-#  restricted_signup_domains    :text
-#  user_oauth_applications      :boolean          default(TRUE)
-#  after_sign_out_path          :string(255)
-#  session_expire_delay         :integer          default(10080), not null
-#  import_sources               :text
-#  help_page_text               :text
-#  admin_notification_email     :string(255)
-#  shared_runners_enabled       :boolean          default(TRUE), not null
-#  max_artifacts_size           :integer          default(100), not null
-#  runners_registration_token   :string(255)
+#  id                                :integer          not null, primary key
+#  default_projects_limit            :integer
+#  signup_enabled                    :boolean
+#  signin_enabled                    :boolean
+#  gravatar_enabled                  :boolean
+#  sign_in_text                      :text
+#  created_at                        :datetime
+#  updated_at                        :datetime
+#  home_page_url                     :string(255)
+#  default_branch_protection         :integer          default(2)
+#  twitter_sharing_enabled           :boolean          default(TRUE)
+#  restricted_visibility_levels      :text
+#  version_check_enabled             :boolean          default(TRUE)
+#  max_attachment_size               :integer          default(10), not null
+#  default_project_visibility        :integer
+#  default_snippet_visibility        :integer
+#  restricted_signup_domains         :text
+#  user_oauth_applications           :boolean          default(TRUE)
+#  after_sign_out_path               :string(255)
+#  session_expire_delay              :integer          default(10080), not null
+#  import_sources                    :text
+#  help_page_text                    :text
+#  admin_notification_email          :string(255)
+#  shared_runners_enabled            :boolean          default(TRUE), not null
+#  max_artifacts_size                :integer          default(100), not null
+#  runners_registration_token        :string(255)
+#  require_two_factor_authentication :boolean          default(TRUE)
+#  two_factor_grace_period           :integer          default(48)
 #
 
 class ApplicationSetting < ActiveRecord::Base
@@ -58,6 +60,9 @@ class ApplicationSetting < ActiveRecord::Base
     allow_blank: true,
     email: true
 
+  validates :two_factor_grace_period,
+    numericality: { greater_than_or_equal_to: 0 }
+
   validates_each :restricted_visibility_levels do |record, attr, value|
     unless value.nil?
       value.each do |level|
@@ -112,6 +117,8 @@ class ApplicationSetting < ActiveRecord::Base
       import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'],
       shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
       max_artifacts_size: Settings.artifacts['max_size'],
+      require_two_factor_authentication: false,
+      two_factor_grace_period: 48
     )
   end
 
diff --git a/db/migrate/20151218154042_add_tfa_to_application_settings.rb b/db/migrate/20151218154042_add_tfa_to_application_settings.rb
new file mode 100644
index 0000000000000000000000000000000000000000..dd95db775c5e5e548b8d567223fd8c9dc2607de0
--- /dev/null
+++ b/db/migrate/20151218154042_add_tfa_to_application_settings.rb
@@ -0,0 +1,8 @@
+class AddTfaToApplicationSettings < ActiveRecord::Migration
+  def change
+    change_table :application_settings do |t|
+      t.boolean :require_two_factor_authentication, default: false
+      t.integer :two_factor_grace_period, default: 48
+    end
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0d53105b0570a9239950857b3c1cd84ec3942376..631979a7fd88eef996e934cf823f81d6d0ea61ba 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -50,6 +50,8 @@ ActiveRecord::Schema.define(version: 20151224123230) do
     t.boolean  "shared_runners_enabled",       default: true,  null: false
     t.integer  "max_artifacts_size",           default: 100,   null: false
     t.string   "runners_registration_token"
+    t.boolean  "require_two_factor_authentication",             default: false
+    t.integer  "two_factor_grace_period",                       default: 48
   end
 
   create_table "audit_events", force: :cascade do |t|
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 5f64453a35f29132faf5640052b25314fcdef9e4..35d8220ae548ebce18ae2547f72352eada10e5f8 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -27,6 +27,7 @@
 #  admin_notification_email     :string(255)
 #  shared_runners_enabled       :boolean          default(TRUE), not null
 #  max_artifacts_size           :integer          default(100), not null
+#  runners_registration_token   :string(255)
 #
 
 require 'spec_helper'