class Spid::Saml2::IdpMetadataParser

Auxiliary class to retrieve and parse the Identity Provider Metadata

Constants

DSIG
METADATA
NAME_FORMAT
SAML_ASSERTION

Attributes

document[R]
response[R]

Public Instance Methods

parse_to_hash(idp_metadata) click to toggle source

Parse the Identity Provider metadata and return the results as Hash

@param idp_metadata [String]

@return [Hash]

# File lib/spid/saml2/idp_metadata_parser.rb, line 31
def parse_to_hash(idp_metadata)
  @document = REXML::Document.new(idp_metadata)
  @entity_descriptor = nil
  @certificates = nil

  {
    :idp_entity_id => idp_entity_id,
    :name_identifier_format => idp_name_id_format,
    :idp_sso_target_url => single_signon_service_url,
    :idp_slo_target_url => single_logout_service_url,
    :idp_attribute_names => attribute_names,
    :idp_cert => nil,
    :idp_cert_multi => nil
  }.tap do |response_hash|
    merge_certificates_into(response_hash) unless certificates.nil?
  end
end

Private Instance Methods

attribute_names() click to toggle source

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

# File lib/spid/saml2/idp_metadata_parser.rb, line 165
def attribute_names
  nodes = REXML::XPath.match(
    entity_descriptor,
    "md:IDPSSODescriptor/saml:Attribute/@Name",
    namespace
  )
  nodes.map(&:value)
end
certificates() click to toggle source

@return [String|nil] Unformatted Certificate if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 128
def certificates
  @certificates ||= begin
    signing_nodes = REXML::XPath.match(
      entity_descriptor,
      "md:IDPSSODescriptor/md:KeyDescriptor[not(contains(@use, 'encryption'))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate",
      namespace
    )

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

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

      unless encryption_nodes.empty?
        certs['encryption'] = []
        encryption_nodes.each do |cert_node|
          certs['encryption'] << element_text(cert_node)
        end
      end
    end
    certs
  end
end
element_text(element) click to toggle source
# File lib/spid/saml2/idp_metadata_parser.rb, line 194
def element_text(element)
  element.texts.map(&:value).join if element
end
entity_descriptor() click to toggle source
# File lib/spid/saml2/idp_metadata_parser.rb, line 51
def entity_descriptor
  @entity_descriptor ||= REXML::XPath.first(
    document,
    "//md:EntityDescriptor",
    namespace
  )
end
idp_entity_id() click to toggle source

@return [String|nil] IdP Entity ID value if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 61
def idp_entity_id
  entity_descriptor.attributes["entityID"]
end
idp_name_id_format() click to toggle source

@return [String|nil] IdP Name ID Format value if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 67
def idp_name_id_format
  node = REXML::XPath.first(
    entity_descriptor,
    "md:IDPSSODescriptor/md:NameIDFormat",
    namespace
  )
  element_text(node)
end
merge_certificates_into(parsed_metadata) click to toggle source
# File lib/spid/saml2/idp_metadata_parser.rb, line 183
def merge_certificates_into(parsed_metadata)
    if certificates.key?("signing")
      certificate = certificates["signing"][0]
    else
      certificate = certificates["encryption"][0]
    end
    parsed_metadata[:idp_cert] = OpenSSL::X509::Certificate.new(
      Base64.decode64(certificate)
    )
end
namespace() click to toggle source
# File lib/spid/saml2/idp_metadata_parser.rb, line 174
def namespace
  {
    "md" => METADATA,
    "NameFormat" => NAME_FORMAT,
    "saml" => SAML_ASSERTION,
    "ds" => DSIG
  }
end
single_logout_service_binding() click to toggle source

@return [String|nil] SingleLogoutService binding if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 103
def single_logout_service_binding
  nodes = REXML::XPath.match(
    entity_descriptor,
    "md:IDPSSODescriptor/md:SingleLogoutService/@Binding",
    namespace
  )
  nodes.first.value if nodes.any?
end
single_logout_service_url() click to toggle source

@return [String|nil] SingleLogoutService endpoint if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 114
def single_logout_service_url
  binding = single_logout_service_binding
  unless binding.nil?
    node = REXML::XPath.first(
      entity_descriptor,
      "md:IDPSSODescriptor/md:SingleLogoutService[@Binding=\"#{binding}\"]/@Location",
      namespace
    )
    return node.value if node
  end
end
single_signon_service_binding() click to toggle source

@return [String|nil] SingleSignOnService binding if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 78
def single_signon_service_binding
  nodes = REXML::XPath.match(
    entity_descriptor,
    "md:IDPSSODescriptor/md:SingleSignOnService/@Binding",
    namespace
  )
  nodes.first.value if nodes.any?
end
single_signon_service_url() click to toggle source

@return [String|nil] SingleSignOnService endpoint if exists

# File lib/spid/saml2/idp_metadata_parser.rb, line 89
def single_signon_service_url
  binding = single_signon_service_binding
  unless binding.nil?
    node = REXML::XPath.first(
      entity_descriptor,
      "md:IDPSSODescriptor/md:SingleSignOnService[@Binding=\"#{binding}\"]/@Location",
      namespace
    )
    return node.value if node
  end
end