diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2dc99a01f..c93642753 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -129,7 +129,14 @@ class ApplicationController < ActionController::Base elsif /\ABasic /i.match?(request.authorization.to_s) # HTTP Basic, either username/password or API key/random authenticate_with_http_basic do |username, password| - user = User.try_to_login(username, password) || User.find_by_api_key(username) + user = User.try_to_login(username, password) + # Don't allow using username/password when two-factor auth is active + if user&.twofa_active? + render_error :message => 'HTTP Basic authentication is not allowed. Use API key instead', :status => 401 + return + end + + user ||= User.find_by_api_key(username) end if user && user.must_change_password? render_error :message => 'You must change your password', :status => 403 diff --git a/test/integration/api_test/authentication_test.rb b/test/integration/api_test/authentication_test.rb index 60d787ea8..18838487c 100644 --- a/test/integration/api_test/authentication_test.rb +++ b/test/integration/api_test/authentication_test.rb @@ -48,6 +48,15 @@ class Redmine::ApiTest::AuthenticationTest < Redmine::ApiTest::Base assert_response 401 end + def test_api_should_deny_http_basic_auth_if_twofa_is_active + user = User.generate! do |user| + user.password = 'my_password' + user.update(twofa_scheme: 'totp') + end + get '/users/current.xml', :headers => credentials(user.login, 'my_password') + assert_response 401 + end + def test_api_should_accept_http_basic_auth_using_api_key user = User.generate! token = Token.create!(:user => user, :action => 'api')