class OneLogin::RubySaml::IdpMetadataParser

Auxiliary class to retrieve and parse the Identity Provider Metadata

This class does not validate in any way the URL that is introduced, make sure to validate it properly before use it in a parse_remote method. Read the ‘Security warning` section of the README.md file to get more info

Attributes

document[R]
options[R]
response[R]

Public Class Methods

get_idps(metadata_document, only_entity_id=nil) click to toggle source

fetch IdP descriptors from a metadata document

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 42
def self.get_idps(metadata_document, only_entity_id=nil)
  path = "//md:EntityDescriptor#{only_entity_id && '[@entityID="' + only_entity_id + '"]'}/md:IDPSSODescriptor"
  REXML::XPath.match(
    metadata_document,
    path,
    SamlMetadata::NAMESPACE
  )
end

Public Instance Methods

get_idp_metadata(url, validate_cert) click to toggle source

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. @return [REXML::document] Parsed XML IdP metadata @raise [HttpError] Failure to fetch remote IdP metadata

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 194
def get_idp_metadata(url, validate_cert)
  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)

  if uri.scheme == "https"
    http.use_ssl = true
    # Most IdPs will probably use self signed certs
    http.verify_mode = validate_cert ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE

    # Net::HTTP in Ruby 1.8 did not set the default certificate store
    # automatically when VERIFY_PEER was specified.
    if RUBY_VERSION < '1.9' && !http.ca_file && !http.ca_path && !http.cert_store
      http.cert_store = OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE
    end
  end

  get = Net::HTTP::Get.new(uri.request_uri)
  get.basic_auth uri.user, uri.password if uri.user
  @response = http.request(get)
  return response.body if response.is_a? Net::HTTPSuccess

  raise OneLogin::RubySaml::HttpError.new(
    "Failed to fetch idp metadata: #{response.code}: #{response.message}"
  )
end
parse(idp_metadata, options = {}) click to toggle source

Parse the Identity Provider metadata and update the settings with the IdP values

@param idp_metadata [String]

@param options [Hash] :settings to provide the OneLogin::RubySaml::Settings object or an hash for Settings overrides @option options [OneLogin::RubySaml::Settings, Hash] :settings the OneLogin::RubySaml::Settings object which gets the parsed metadata merged into or an hash for Settings overrides. @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used. @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used. @option options [String, Array<String>, 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<String>, 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.

@return [OneLogin::RubySaml::Settings]

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 121
def parse(idp_metadata, options = {})
  parsed_metadata = parse_to_hash(idp_metadata, options)

  unless parsed_metadata[:cache_duration].nil?
    cache_valid_until_timestamp = OneLogin::RubySaml::Utils.parse_duration(parsed_metadata[:cache_duration])
    unless cache_valid_until_timestamp.nil?
      if parsed_metadata[:valid_until].nil? || cache_valid_until_timestamp < Time.parse(parsed_metadata[:valid_until], Time.now.utc).to_i
        parsed_metadata[:valid_until] = Time.at(cache_valid_until_timestamp).utc.strftime("%Y-%m-%dT%H:%M:%SZ")
      end
    end
  end
  # Remove the cache_duration because on the settings
  # we only gonna suppot valid_until
  parsed_metadata.delete(:cache_duration)

  settings = options[:settings]

  if settings.nil?
    OneLogin::RubySaml::Settings.new(parsed_metadata)
  elsif settings.is_a?(Hash)
    OneLogin::RubySaml::Settings.new(settings.merge(parsed_metadata))
  else
    merge_parsed_metadata_into(settings, parsed_metadata)
  end
end
parse_remote(url, validate_cert = true, options = {}) click to toggle source

Parse the Identity Provider metadata and update the settings with the IdP values

@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 options [Hash] options used for parsing the metadata and the returned Settings instance @option options [OneLogin::RubySaml::Settings, Hash] :settings the OneLogin::RubySaml::Settings object which gets the parsed metadata merged into or an hash for Settings overrides. @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used. @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used. @option options [String, Array<String>, 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<String>, 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.

@return [OneLogin::RubySaml::Settings]

@raise [HttpError] Failure to fetch remote IdP metadata

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 67
def parse_remote(url, validate_cert = true, options = {})
  idp_metadata = get_idp_metadata(url, validate_cert)
  parse(idp_metadata, options)
end
parse_remote_to_array(url, validate_cert = true, options = {}) click to toggle source

Parse all Identity Provider metadata and return the results as Array

@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 options [Hash] options used for parsing the metadata @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, all found IdPs are returned. @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used. @option options [String, Array<String>, 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<String>, 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.

@return [Array<Hash>]

@raise [HttpError] Failure to fetch remote IdP metadata

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 104
def parse_remote_to_array(url, validate_cert = true, options = {})
  idp_metadata = get_idp_metadata(url, validate_cert)
  parse_to_array(idp_metadata, options)
end
parse_remote_to_hash(url, validate_cert = true, options = {}) click to toggle source

Parse the Identity Provider metadata and return the results as Hash

@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 options [Hash] options used for parsing the metadata @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used. @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used. @option options [String, Array<String>, 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<String>, 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.

@return [Hash]

@raise [HttpError] Failure to fetch remote IdP metadata

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 86
def parse_remote_to_hash(url, validate_cert = true, options = {})
  parse_remote_to_array(url, validate_cert, options)[0]
end
parse_to_array(idp_metadata, options = {}) click to toggle source

Parse all Identity Provider metadata and return the results as Array

@param idp_metadata [String]

@param options [Hash] options used for parsing the metadata and the returned Settings instance @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, all found IdPs are returned. @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used. @option options [String, Array<String>, 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<String>, 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.

@return [Array<Hash>]

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 173
def parse_to_array(idp_metadata, options = {})
  parse_to_idp_metadata_array(idp_metadata, options).map { |idp_md| idp_md.to_hash(options) }
end
parse_to_hash(idp_metadata, options = {}) click to toggle source

Parse the Identity Provider metadata and return the results as Hash

@param idp_metadata [String]

@param options [Hash] options used for parsing the metadata and the returned Settings instance @option options [String, nil] :entity_id when this is given, the entity descriptor for this ID is used. When omitted, the first entity descriptor is used. @option options [String, Array<String>, nil] :sso_binding an ordered list of bindings to detect the single signon URL. The first binding in the list that is included in the metadata will be used. @option options [String, Array<String>, 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<String>, 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.

@return [Hash]

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 158
def parse_to_hash(idp_metadata, options = {})
  parse_to_array(idp_metadata, options)[0]
end
parse_to_idp_metadata_array(idp_metadata, options = {}) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 177
def parse_to_idp_metadata_array(idp_metadata, options = {})
  @document = REXML::Document.new(idp_metadata)
  @options = options

  idpsso_descriptors = self.class.get_idps(@document, options[:entity_id])
  if !idpsso_descriptors.any?
    raise ArgumentError.new("idp_metadata must contain an IDPSSODescriptor element")
  end

  idpsso_descriptors.map {|id| IdpMetadata.new(id, id.parent.attributes["entityID"])}
end

Private Instance Methods

merge_parsed_metadata_into(settings, parsed_metadata) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 464
def merge_parsed_metadata_into(settings, parsed_metadata)
  parsed_metadata.each do |key, value|
    settings.send("#{key}=".to_sym, value)
  end

  settings
end