diff --git a/lib/onelogin/ruby-saml/idp_metadata_parser.rb b/lib/onelogin/ruby-saml/idp_metadata_parser.rb index d4205896..82d72e5a 100644 --- a/lib/onelogin/ruby-saml/idp_metadata_parser.rb +++ b/lib/onelogin/ruby-saml/idp_metadata_parser.rb @@ -61,11 +61,16 @@ def self.get_idps(metadata_document, only_entity_id=nil) # @option options [String, Array, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used. # @option options [String, Array, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used. # + # @param request_options [Hash] options used for requesting the remote URL + # @option request_options [Numeric, nil] :open_timeout Number of seconds to wait for the connection to open. See Net::HTTP#open_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Numeric, nil] :read_timeout Number of seconds to wait for one block to be read. See Net::HTTP#read_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Integer, nil] :max_retries Maximum number of times to retry the request on certain errors. See Net::HTTP#max_retries= for more info. Default is the Net::HTTP default. + # # @return [OneLogin::RubySaml::Settings] # # @raise [HttpError] Failure to fetch remote IdP metadata - def parse_remote(url, validate_cert = true, options = {}) - idp_metadata = get_idp_metadata(url, validate_cert) + def parse_remote(url, validate_cert = true, options = {}, request_options = {}) + idp_metadata = get_idp_metadata(url, validate_cert, request_options) parse(idp_metadata, options) end @@ -80,11 +85,16 @@ def parse_remote(url, validate_cert = true, options = {}) # @option options [String, Array, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used. # @option options [String, Array, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used. # + # @param request_options [Hash] options used for requesting the remote URL + # @option request_options [Numeric, nil] :open_timeout Number of seconds to wait for the connection to open. See Net::HTTP#open_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Numeric, nil] :read_timeout Number of seconds to wait for one block to be read. See Net::HTTP#read_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Integer, nil] :max_retries Maximum number of times to retry the request on certain errors. See Net::HTTP#max_retries= for more info. Default is the Net::HTTP default. + # # @return [Hash] # # @raise [HttpError] Failure to fetch remote IdP metadata - def parse_remote_to_hash(url, validate_cert = true, options = {}) - parse_remote_to_array(url, validate_cert, options)[0] + def parse_remote_to_hash(url, validate_cert = true, options = {}, request_options = {}) + parse_remote_to_array(url, validate_cert, request_options, options)[0] end # Parse all Identity Provider metadata and return the results as Array @@ -98,11 +108,16 @@ def parse_remote_to_hash(url, validate_cert = true, options = {}) # @option options [String, Array, nil] :slo_binding an ordered list of bindings to detect the single logout URL. The first binding in the list that is included in the metadata will be used. # @option options [String, Array, nil] :name_id_format an ordered list of NameIDFormats to detect a desired value. The first NameIDFormat in the list that is included in the metadata will be used. # + # @param request_options [Hash] options used for requesting the remote URL + # @option request_options [Numeric, nil] :open_timeout Number of seconds to wait for the connection to open. See Net::HTTP#open_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Numeric, nil] :read_timeout Number of seconds to wait for one block to be read. See Net::HTTP#read_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Integer, nil] :max_retries Maximum number of times to retry the request on certain errors. See Net::HTTP#max_retries= for more info. Default is the Net::HTTP default. + # # @return [Array] # # @raise [HttpError] Failure to fetch remote IdP metadata - def parse_remote_to_array(url, validate_cert = true, options = {}) - idp_metadata = get_idp_metadata(url, validate_cert) + def parse_remote_to_array(url, validate_cert = true, options = {}, request_options = {}) + idp_metadata = get_idp_metadata(url, validate_cert, request_options) parse_to_array(idp_metadata, options) end @@ -191,9 +206,13 @@ def parse_to_idp_metadata_array(idp_metadata, options = {}) # Retrieve the remote IdP metadata from the URL or a cached copy. # @param url [String] Url where the XML of the Identity Provider Metadata is published. # @param validate_cert [Boolean] If true and the URL is HTTPs, the cert of the domain is checked. + # @param request_options [Hash] options used for requesting the remote URL + # @option request_options [Numeric, nil] :open_timeout Number of seconds to wait for the connection to open. See Net::HTTP#open_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Numeric, nil] :read_timeout Number of seconds to wait for one block to be read. See Net::HTTP#read_timeout for more info. Default is the Net::HTTP default. + # @option request_options [Integer, nil] :max_retries Maximum number of times to retry the request on certain errors. See Net::HTTP#max_retries= for more info. Default is the Net::HTTP default. # @return [REXML::document] Parsed XML IdP metadata # @raise [HttpError] Failure to fetch remote IdP metadata - def get_idp_metadata(url, validate_cert) + def get_idp_metadata(url, validate_cert, request_options) uri = URI.parse(url) raise ArgumentError.new("url must begin with http or https") unless /^https?/ =~ uri.scheme http = Net::HTTP.new(uri.host, uri.port) @@ -210,6 +229,10 @@ def get_idp_metadata(url, validate_cert) end end + http.open_timeout = request_options[:open_timeout] if request_options[:open_timeout] + http.read_timeout = request_options[:read_timeout] if request_options[:read_timeout] + http.max_retries = request_options[:max_retries] if request_options[:max_retries] + get = Net::HTTP::Get.new(uri.request_uri) get.basic_auth uri.user, uri.password if uri.user @response = http.request(get) diff --git a/test/idp_metadata_parser_test.rb b/test/idp_metadata_parser_test.rb index cb6d1f4d..7e937daa 100644 --- a/test/idp_metadata_parser_test.rb +++ b/test/idp_metadata_parser_test.rb @@ -335,6 +335,19 @@ def initialize; end assert_equal OpenSSL::SSL::VERIFY_NONE, @http.verify_mode end + + it "allows setting HTTP options on the request" do + refute_equal 2, @http.open_timeout + refute_equal 3, @http.read_timeout + refute_equal 4, @http.max_retries + + idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new + settings = idp_metadata_parser.parse_remote(@url, true, {}, open_timeout: 2, read_timeout: 3, max_retries: 4) + + assert_equal 2, @http.open_timeout + assert_equal 3, @http.read_timeout + assert_equal 4, @http.max_retries + end end describe "download and parse IdP descriptor file into an Hash" do