diff --git a/app/controllers/epp/base_controller.rb b/app/controllers/epp/base_controller.rb
index 12efbd1d3..520b97c4f 100644
--- a/app/controllers/epp/base_controller.rb
+++ b/app/controllers/epp/base_controller.rb
@@ -21,12 +21,22 @@ module Epp
rescue_from StandardError, with: :respond_with_command_failed_error
rescue_from AuthorizationError, with: :respond_with_authorization_error
rescue_from ActiveRecord::RecordNotFound, with: :respond_with_object_does_not_exist_error
+ rescue_from Shunter::ThrottleError, with: :respond_with_session_limit_exceeded_error
+
before_action :set_paper_trail_whodunnit
skip_before_action :validate_against_schema
protected
+ def respond_with_session_limit_exceeded_error(exception)
+ epp_errors.add(:epp_errors,
+ code: '2502',
+ message: 'Session limit exceeded, try again later')
+ handle_errors
+ log_exception(exception)
+ end
+
def respond_with_command_failed_error(exception)
epp_errors.add(:epp_errors,
code: '2400',
@@ -51,6 +61,11 @@ module Epp
private
+ def throttled_user
+ authorize!(:throttled_user, @domain) unless current_user
+ current_user
+ end
+
def wrap_exceptions
yield
rescue CanCan::AccessDenied
diff --git a/app/controllers/epp/contacts_controller.rb b/app/controllers/epp/contacts_controller.rb
index 10250563c..5509507d3 100644
--- a/app/controllers/epp/contacts_controller.rb
+++ b/app/controllers/epp/contacts_controller.rb
@@ -5,6 +5,9 @@ module Epp
before_action :find_contact, only: [:info, :update, :delete]
before_action :find_password, only: [:info, :update, :delete]
+ THROTTLED_ACTIONS = %i[info renew update transfer delete].freeze
+ include Shunter::Integration::Throttle
+
def info
authorize! :info, @contact, @password
render_epp_response 'epp/contacts/info'
diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb
index 49ea43ae0..a05b56531 100644
--- a/app/controllers/epp/domains_controller.rb
+++ b/app/controllers/epp/domains_controller.rb
@@ -134,11 +134,6 @@ module Epp
private
- def throttled_user
- authorize!(:throttled_user, @domain) unless current_user
- current_user
- end
-
def validate_info
@prefix = 'info > info >'
requires('name')
diff --git a/config/application.yml.sample b/config/application.yml.sample
index 5b01624cf..b8b9b12d0 100644
--- a/config/application.yml.sample
+++ b/config/application.yml.sample
@@ -198,6 +198,7 @@ test:
dnssec_resolver_ips: 8.8.8.8, 8.8.4.4
legal_documents_dir: 'test/fixtures/files'
shunter_default_adapter: "Shunter::Adapters::Memory"
+ shunter_enabled: "false"
openssl_config_path: 'test/fixtures/files/test_ca/openssl.cnf'
crl_dir: 'test/fixtures/files/test_ca/crl'
diff --git a/test/integration/epp/domain/info/base_test.rb b/test/integration/epp/domain/info/base_test.rb
index da3be1d38..99de33f29 100644
--- a/test/integration/epp/domain/info/base_test.rb
+++ b/test/integration/epp/domain/info/base_test.rb
@@ -1,6 +1,11 @@
require 'test_helper'
class EppDomainInfoBaseTest < EppTestCase
+ setup do
+ adapter = ENV["shunter_default_adapter"].constantize.new
+ adapter&.clear!
+ end
+
def test_returns_valid_response
assert_equal 'john-001', contacts(:john).code
domains(:shop).update_columns(statuses: [DomainStatus::OK],
@@ -180,6 +185,61 @@ class EppDomainInfoBaseTest < EppTestCase
assert_correct_against_schema response_xml
end
+ def test_returns_valid_response_if_not_throttled
+ domain = domains(:shop)
+
+ request_xml = <<-XML
+
+
+
+
+
+ #{domain.name}
+
+
+
+
+ XML
+
+ post epp_info_path, params: { frame: request_xml },
+ headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
+
+ response_xml = Nokogiri::XML(response.body)
+ assert_epp_response :completed_successfully
+ assert_correct_against_schema response_xml
+ end
+
+ def test_returns_error_response_if_throttled
+ ENV["shunter_default_threshold"] = '1'
+ ENV["shunter_enabled"] = 'true'
+ domain = domains(:shop)
+
+ request_xml = <<-XML
+
+
+
+
+
+ #{domain.name}
+
+
+
+
+ XML
+
+ post epp_info_path, params: { frame: request_xml },
+ headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
+
+ post epp_info_path, params: { frame: request_xml },
+ headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
+
+ response_xml = Nokogiri::XML(response.body)
+ assert_epp_response :session_limit_exceeded_server_closing_connection
+ assert_correct_against_schema response_xml
+ ENV["shunter_default_threshold"] = '10000'
+ ENV["shunter_enabled"] = 'false'
+ end
+
def test_returns_valid_response_if_release_prohibited
domain = domains(:shop)
domain.update_columns(statuses: [DomainStatus::SERVER_RELEASE_PROHIBITED],