lib/saml/kit/metadata.rb in saml-kit-1.0.9 vs lib/saml/kit/metadata.rb in saml-kit-1.0.10
- old
+ new
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
module Saml
module Kit
# The Metadata object can be used to parse an XML string of metadata.
#
# metadata = Saml::Kit::Metadata.from(raw_xml)
@@ -27,15 +29,15 @@
include XsdValidatable
include Translatable
include Buildable
METADATA_XSD = File.expand_path('./xsd/saml-schema-metadata-2.0.xsd', File.dirname(__FILE__)).freeze
NAMESPACES = {
- "NameFormat": Namespaces::ATTR_SPLAT,
- "ds": ::Xml::Kit::Namespaces::XMLDSIG,
- "md": Namespaces::METADATA,
- "saml": Namespaces::ASSERTION,
- "samlp": Namespaces::PROTOCOL,
+ NameFormat: Namespaces::ATTR_SPLAT,
+ ds: ::Xml::Kit::Namespaces::XMLDSIG,
+ md: Namespaces::METADATA,
+ saml: Namespaces::ASSERTION,
+ samlp: Namespaces::PROTOCOL,
}.freeze
validates_presence_of :metadata
validate :must_contain_descriptor
validate :must_match_xsd
@@ -48,40 +50,38 @@
@xml = xml
end
# Returns the /EntityDescriptor/@entityID
def entity_id
- document.find_by('/md:EntityDescriptor/@entityID').value
+ at_xpath('/md:EntityDescriptor/@entityID').try(:value)
end
# Returns the supported NameIDFormats.
def name_id_formats
- document.find_all("/md:EntityDescriptor/md:#{name}/md:NameIDFormat").map(&:text)
+ search("/md:EntityDescriptor/md:#{name}/md:NameIDFormat").map(&:text)
end
# Returns the Organization Name
def organization_name
- document.find_by('/md:EntityDescriptor/md:Organization/md:OrganizationName').try(:text)
+ at_xpath('/md:EntityDescriptor/md:Organization/md:OrganizationName').try(:text)
end
# Returns the Organization URL
def organization_url
- document.find_by('/md:EntityDescriptor/md:Organization/md:OrganizationURL').try(:text)
+ at_xpath('/md:EntityDescriptor/md:Organization/md:OrganizationURL').try(:text)
end
# Returns the Company
def contact_person_company
- document.find_by('/md:EntityDescriptor/md:ContactPerson/md:Company').try(:text)
+ at_xpath('/md:EntityDescriptor/md:ContactPerson/md:Company').try(:text)
end
# Returns each of the X509 certificates.
def certificates
- @certificates ||= document.find_all("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
- cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', NAMESPACES).text
- attribute = item.attribute('use')
- use = attribute.nil? ? nil : item.attribute('use').value
- ::Xml::Kit::Certificate.new(cert, use: use)
+ @certificates ||= search("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
+ cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', 'ds' => ::Xml::Kit::Namespaces::XMLDSIG).try(:text)
+ ::Xml::Kit::Certificate.new(cert, use: item.attribute('use').try(:value))
end
end
# Returns the encryption certificates
def encryption_certificates
@@ -95,11 +95,11 @@
# Returns each of the service endpoints supported by this metadata.
#
# @param type [String] the type of service. .E.g. `AssertionConsumerServiceURL`
def services(type)
- document.find_all("/md:EntityDescriptor/md:#{name}/md:#{type}").map do |item|
+ search("/md:EntityDescriptor/md:#{name}/md:#{type}").map do |item|
binding = item.attribute('Binding').value
location = item.attribute('Location').value
Saml::Kit::Bindings.create_for(binding, location)
end
end
@@ -130,26 +130,22 @@
# @param user [Object] a user object that responds to `name_id_for` and `assertion_attributes_for`.
# @param binding [Symbol] can be `:http_post` or `:http_redirect`.
# @param relay_state [String] the relay state to have echo'd back.
# @return [Array] Returns an array with a url and Hash of parameters to send to the other party.
def logout_request_for(user, binding: :http_post, relay_state: nil)
- builder = Saml::Kit::LogoutRequest.builder(user) do |x|
- yield x if block_given?
- end
+ builder = Saml::Kit::LogoutRequest.builder(user) { |x| yield x if block_given? }
request_binding = single_logout_service_for(binding: binding)
request_binding.serialize(builder, relay_state: relay_state)
end
# Returns the certificate that matches the fingerprint
#
# @param fingerprint [Saml::Kit::Fingerprint] the fingerprint to search for.
# @param use [Symbol] the type of certificates to look at. Can be `:signing` or `:encryption`.
# @return [Xml::Kit::Certificate] returns the matching `{Xml::Kit::Certificate}`
def matches?(fingerprint, use: :signing)
- certificates.find do |certificate|
- certificate.for?(use) && certificate.fingerprint == fingerprint
- end
+ certificates.find { |x| x.for?(use) && x.fingerprint == fingerprint }
end
# Returns the XML document converted to a Hash.
def to_h
@xml_hash ||= Hash.from_xml(to_xml)
@@ -157,11 +153,11 @@
# Returns the XML document as a String.
#
# @param pretty [Symbol] true to return a human friendly version of the XML.
def to_xml(pretty: false)
- document.to_xml(pretty: pretty)
+ pretty ? to_nokogiri.to_xml(indent: 2) : @xml
end
# Returns the XML document as a [String].
def to_s
to_xml
@@ -187,17 +183,19 @@
# Creates a `{Saml::Kit::Metadata}` object from a raw XML [String].
#
# @param content [String] the raw metadata XML.
# @return [Saml::Kit::Metadata] the metadata document or subclass.
def from(content)
- hash = Hash.from_xml(content)
- entity_descriptor = hash['EntityDescriptor']
- if entity_descriptor.key?('SPSSODescriptor') && entity_descriptor.key?('IDPSSODescriptor')
+ document = Nokogiri::XML(content)
+ return unless document.at_xpath('/md:EntityDescriptor', NAMESPACES)
+ sp = document.at_xpath('/md:EntityDescriptor/md:SPSSODescriptor', NAMESPACES)
+ idp = document.at_xpath('/md:EntityDescriptor/md:IDPSSODescriptor', NAMESPACES)
+ if sp && idp
Saml::Kit::CompositeMetadata.new(content)
- elsif entity_descriptor.keys.include?('SPSSODescriptor')
+ elsif sp
Saml::Kit::ServiceProviderMetadata.new(content)
- elsif entity_descriptor.keys.include?('IDPSSODescriptor')
+ elsif idp
Saml::Kit::IdentityProviderMetadata.new(content)
end
end
# @!visibility private
@@ -208,19 +206,24 @@
private
attr_reader :xml
- def document
- @document ||= ::Xml::Kit::Document.new(xml, namespaces: NAMESPACES)
+ # @!visibility private
+ def to_nokogiri
+ @nokogiri ||= Nokogiri::XML(xml)
end
def at_xpath(xpath)
- document.find_by(xpath)
+ to_nokogiri.at_xpath(xpath, NAMESPACES)
end
+ def search(xpath)
+ to_nokogiri.search(xpath, NAMESPACES)
+ end
+
def metadata
- document.find_by("/md:EntityDescriptor/md:#{name}").present?
+ at_xpath("/md:EntityDescriptor/md:#{name}").present?
end
def must_contain_descriptor
errors[:base] << error_message(:invalid) unless metadata
end