class OneLogin::RubySaml::IdpMetadataParser::IdpMetadata

Attributes

entity_id[R]
idpsso_descriptor[R]

Public Class Methods

new(idpsso_descriptor, entity_id) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 226
def initialize(idpsso_descriptor, entity_id)
  @idpsso_descriptor = idpsso_descriptor
  @entity_id = entity_id
end

Public Instance Methods

attribute_names() click to toggle source

@return [Array] the names of all SAML attributes if any exist

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 399
def attribute_names
  nodes = REXML::XPath.match(
    @idpsso_descriptor  ,
    "saml:Attribute/@Name",
    SamlMetadata::NAMESPACE
  )
  nodes.map(&:value)
end
cache_duration() click to toggle source

@return [String|nil] ‘cacheDuration’ attribute of metadata

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 262
def cache_duration
  root = @idpsso_descriptor.root
  root.attributes['cacheDuration'] if root && root.attributes
end
certificates() click to toggle source

@return [String|nil] Unformatted Certificate if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 350
def certificates
  @certificates ||= begin
    signing_nodes = REXML::XPath.match(
      @idpsso_descriptor,
      "md:KeyDescriptor[not(contains(@use, 'encryption'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate",
      SamlMetadata::NAMESPACE
    )

    encryption_nodes = REXML::XPath.match(
      @idpsso_descriptor,
      "md:KeyDescriptor[not(contains(@use, 'signing'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate",
      SamlMetadata::NAMESPACE
    )

    return nil if signing_nodes.empty? && encryption_nodes.empty?

    certs = {}
    unless signing_nodes.empty?
      certs['signing'] = []
      signing_nodes.each do |cert_node|
        certs['signing'] << Utils.element_text(cert_node)
      end
    end

    unless encryption_nodes.empty?
      certs['encryption'] = []
      encryption_nodes.each do |cert_node|
        certs['encryption'] << Utils.element_text(cert_node)
      end
    end
    certs
  end
end
certificates_has_one(key) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 433
def certificates_has_one(key)
  certificates.key?(key) && certificates[key].size == 1
end
fingerprint(certificate, fingerprint_algorithm = XMLSecurity::Document::SHA1) click to toggle source

@return [String|nil] the fingerpint of the X509Certificate if it exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 386
def fingerprint(certificate, fingerprint_algorithm = XMLSecurity::Document::SHA1)
  @fingerprint ||= begin
    return unless certificate

    cert = OpenSSL::X509::Certificate.new(Base64.decode64(certificate))

    fingerprint_alg = XMLSecurity::BaseDocument.new.algorithm(fingerprint_algorithm).new
    fingerprint_alg.hexdigest(cert.to_der).upcase.scan(/../).join(":")
  end
end
idp_name_id_format(name_id_priority = nil) click to toggle source

@param name_id_priority [String|Array<String>] The prioritized list of NameIDFormat values to select. Will select first value if nil. @return [String|nil] IdP NameIDFormat value if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 270
def idp_name_id_format(name_id_priority = nil)
  nodes = REXML::XPath.match(
    @idpsso_descriptor,
    "md:NameIDFormat",
    SamlMetadata::NAMESPACE
  )
  first_ranked_text(nodes, name_id_priority)
end
merge_certificates_into(parsed_metadata) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 408
def merge_certificates_into(parsed_metadata)
  if (certificates.size == 1 &&
      (certificates_has_one('signing') || certificates_has_one('encryption'))) ||
      (certificates_has_one('signing') && certificates_has_one('encryption') &&
      certificates["signing"][0] == certificates["encryption"][0])

    if certificates.key?("signing")
      parsed_metadata[:idp_cert] = certificates["signing"][0]
      parsed_metadata[:idp_cert_fingerprint] = fingerprint(
        parsed_metadata[:idp_cert],
        parsed_metadata[:idp_cert_fingerprint_algorithm]
      )
    else
      parsed_metadata[:idp_cert] = certificates["encryption"][0]
      parsed_metadata[:idp_cert_fingerprint] = fingerprint(
        parsed_metadata[:idp_cert],
        parsed_metadata[:idp_cert_fingerprint_algorithm]
      )
    end
  end

  # symbolize keys of certificates and pass it on
  parsed_metadata[:idp_cert_multi] = Hash[certificates.map { |k, v| [k.to_sym, v] }]
end
single_logout_response_service_url(binding_priority = nil) click to toggle source

@param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil. @return [String|nil] SingleLogoutService response url if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 336
def single_logout_response_service_url(binding_priority = nil)
  binding = single_logout_service_binding(binding_priority)
  return if binding.nil?

  node = REXML::XPath.first(
    @idpsso_descriptor,
    "md:SingleLogoutService[@Binding=\"#{binding}\"]/@ResponseLocation",
    SamlMetadata::NAMESPACE
  )
  node.value if node
end
single_logout_service_binding(binding_priority = nil) click to toggle source

@param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil. @return [String|nil] SingleLogoutService binding if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 294
def single_logout_service_binding(binding_priority = nil)
  nodes = REXML::XPath.match(
    @idpsso_descriptor,
    "md:SingleLogoutService/@Binding",
    SamlMetadata::NAMESPACE
  )
  first_ranked_value(nodes, binding_priority)
end
single_logout_service_url(binding_priority = nil) click to toggle source

@param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil. @return [String|nil] SingleLogoutService endpoint if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 321
def single_logout_service_url(binding_priority = nil)
  binding = single_logout_service_binding(binding_priority)
  return if binding.nil?

  node = REXML::XPath.first(
    @idpsso_descriptor,
    "md:SingleLogoutService[@Binding=\"#{binding}\"]/@Location",
    SamlMetadata::NAMESPACE
  )
  node.value if node
end
single_signon_service_binding(binding_priority = nil) click to toggle source

@param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil. @return [String|nil] SingleSignOnService binding if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 282
def single_signon_service_binding(binding_priority = nil)
  nodes = REXML::XPath.match(
    @idpsso_descriptor,
    "md:SingleSignOnService/@Binding",
    SamlMetadata::NAMESPACE
  )
  first_ranked_value(nodes, binding_priority)
end
single_signon_service_url(binding_priority = nil) click to toggle source

@param binding_priority [String|Array<String>] The prioritized list of Binding values to select. Will select first value if nil. @return [String|nil] SingleSignOnService endpoint if exists

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 306
def single_signon_service_url(binding_priority = nil)
  binding = single_signon_service_binding(binding_priority)
  return if binding.nil?

  node = REXML::XPath.first(
    @idpsso_descriptor,
    "md:SingleSignOnService[@Binding=\"#{binding}\"]/@Location",
    SamlMetadata::NAMESPACE
  )
  node.value if node
end
to_hash(options = {}) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 231
def to_hash(options = {})
  sso_binding = options[:sso_binding]
  slo_binding = options[:slo_binding]
  {
    :idp_entity_id => @entity_id,
    :name_identifier_format => idp_name_id_format(options[:name_id_format]),
    :idp_sso_service_url => single_signon_service_url(sso_binding),
    :idp_sso_service_binding => single_signon_service_binding(sso_binding),
    :idp_slo_service_url => single_logout_service_url(slo_binding),
    :idp_slo_service_binding => single_logout_service_binding(slo_binding),
    :idp_slo_response_service_url => single_logout_response_service_url(slo_binding),
    :idp_attribute_names => attribute_names,
    :idp_cert => nil,
    :idp_cert_fingerprint => nil,
    :idp_cert_multi => nil,
    :valid_until => valid_until,
    :cache_duration => cache_duration,
  }.tap do |response_hash|
    merge_certificates_into(response_hash) unless certificates.nil?
  end
end
valid_until() click to toggle source

@return [String|nil] ‘validUntil’ attribute of metadata

# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 255
def valid_until
  root = @idpsso_descriptor.root
  root.attributes['validUntil'] if root && root.attributes
end

Private Instance Methods

first_ranked_text(nodes, priority = nil) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 439
def first_ranked_text(nodes, priority = nil)
  return unless nodes.any?

  priority = Array(priority)
  if priority.any?
    values = nodes.map(&:text)
    priority.detect { |candidate| values.include?(candidate) }
  else
    nodes.first.text
  end
end
first_ranked_value(nodes, priority = nil) click to toggle source
# File lib/onelogin/ruby-saml/idp_metadata_parser.rb, line 451
def first_ranked_value(nodes, priority = nil)
  return unless nodes.any?

  priority = Array(priority)
  if priority.any?
    values = nodes.map(&:value)
    priority.detect { |candidate| values.include?(candidate) }
  else
    nodes.first.value
  end
end