Class: SAML2::Base Abstract

Inherits:
Object
  • Object
show all
Defined in:
lib/saml2/base.rb

Overview

This class is abstract.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBase

Returns a new instance of Base.



22
23
24
# File 'lib/saml2/base.rb', line 22

def initialize
  @pretty = true
end

Instance Attribute Details

#xmlNokogiri::XML::Element (readonly)

Returns:

  • (Nokogiri::XML::Element)


20
21
22
# File 'lib/saml2/base.rb', line 20

def xml
  @xml
end

Class Method Details

.from_xml(node) ⇒ Base?

Create an appropriate object to represent the given XML element.

Parameters:

  • node (Nokogiri::XML::Element, nil)

Returns:



12
13
14
15
16
17
# File 'lib/saml2/base.rb', line 12

def self.from_xml(node)
  return nil unless node
  result = new
  result.from_xml(node)
  result
end

.load_object_array(node, element, klass = nil) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/saml2/base.rb', line 147

def self.load_object_array(node, element, klass = nil)
  node.xpath(element, Namespaces::ALL).map do |element_node|
    if klass.nil?
      SAML2.const_get(element_node.name, false).from_xml(element_node)
    elsif klass.is_a?(Hash)
      klass[element_node.name].from_xml(element_node)
    else
      klass.from_xml(element_node)
    end
  end
end

.load_string_array(node, element) ⇒ Object



140
141
142
143
144
# File 'lib/saml2/base.rb', line 140

def self.load_string_array(node, element)
  node.xpath(element, Namespaces::ALL).map do |element_node|
    element_node.content&.strip
  end
end

.lookup_qname(qname, namespaces) ⇒ Object



159
160
161
162
# File 'lib/saml2/base.rb', line 159

def self.lookup_qname(qname, namespaces)
  prefix, local_name = split_qname(qname)
  [lookup_namespace(prefix, namespaces), local_name]
end

Instance Method Details

#build(builder) ⇒ void

This method returns an undefined value.

Serialize this object to XML, as part of a larger document

Parameters:

  • builder (Nokogiri::XML::Builder)

    The builder helper object to serialize to.



87
88
# File 'lib/saml2/base.rb', line 87

def build(builder)
end

#decrypt(keys = nil) {|allowed_certs| ... } ⇒ Boolean

Decrypt (in-place) encrypted portions of this object

Either the keys parameter, or a block that returns key(s), should be provided.

Parameters:

  • keys (defaults to: nil)

    optional [Array<OpenSSL::PKey, String>, OpenSSL::PKey, String, nil]

Yields:

  • Optional block to fetch the necessary keys, given information contained in the encrypted elements of which certificates it was encrypted for.

Yield Parameters:

  • allowed_certs (Array<OpenSSL::X509::Certificate, Hash, String, nil>)

    An array of certificates describing who the node was encrypted for. Identified by an X.509 Certificate, a hash with :issuer and :serial keys, or a string of SubjectName.

Yield Returns:

  • (Array<OpenSSL::PKey, String>, OpenSSL::PKey, String, nil)

Returns:

  • (Boolean)

    If any nodes were present.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/saml2/base.rb', line 105

def decrypt(keys = nil)
  encrypted_nodes = self.encrypted_nodes
  encrypted_nodes.each do |node|
    this_nodes_keys = keys
    if keys.nil?
      allowed_certs = node.xpath("dsig:KeyInfo/xenc:EncryptedKey/dsig:KeyInfo/dsig:X509Data", SAML2::Namespaces::ALL).map do |x509data|
        if (cert = x509data.at_xpath("dsig:X509Certificate", SAML2::Namespaces::ALL)&.content&.strip)
          OpenSSL::X509::Certificate.new(Base64.decode64(cert))
        elsif (issuer_serial = x509data.at_xpath("dsig:X509IssuerSerial", SAML2::Namespaces::ALL))
          {
              issuer: issuer_serial.at_xpath("dsig:X509IssuerName", SAML2::Namespaces::ALL).content.strip,
              serial: issuer_serial.at_xpath("dsig:X509SerialNumber", SAML2::Namespaces::ALL).content.strip.to_i,
          }
        elsif (subject_name = x509data.at_xpath("dsig:X509SubjectName", SAML2::Namespaces::ALL)&.content&.strip)
          subject_name
        end
      end
      this_nodes_keys = yield allowed_certs
    end
    this_nodes_keys = Array(this_nodes_keys)
    raise ArgumentError("no decryption key provided or found") if this_nodes_keys.empty?

    old_node = node.parent
    this_nodes_keys.each_with_index do |key, i|
      begin
        old_node.replace(node.decrypt_with(key: key))
      rescue XMLSec::DecryptionError
        # swallow errors on all but the last key
        raise if i - 1 == this_nodes_keys.length
      end
    end
  end
  !encrypted_nodes.empty?
end

#from_xml(node) ⇒ void

This method returns an undefined value.

Parse an XML element into this object.

Parameters:

  • node (Nokogiri::XML::Element)


30
31
32
# File 'lib/saml2/base.rb', line 30

def from_xml(node)
  @xml = node
end

#inspectString

Inspect the object

The @xml instance variable is omitted, keeping this useful. However, if an object lazily parses sub-objects, then their instance variables will not be created until their attribute is accessed.

Returns:

  • (String)


64
65
66
# File 'lib/saml2/base.rb', line 64

def inspect
  "#<#{self.class.name} #{instance_variables.map { |iv| next if iv == :@xml; "#{iv}=#{instance_variable_get(iv).inspect}" }.compact.join(", ") }>"
end

#to_s(pretty: nil) ⇒ String

Returns the XML of this object as a string.

Parameters:

  • pretty (defaults to: nil)

    optional [true, false, nil] true forces it to format it for easy reading. nil will prefer to format it pretty, but won’t if e.g. it has been signed, and pretty formatting would break the signature. If this object came from parsing XML, it will default to exactly what it was parsed as.

Returns:

  • (String)


42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/saml2/base.rb', line 42

def to_s(pretty: nil)
  pretty = @pretty if pretty.nil?
  if xml
    if pretty
      xml.to_s
    else
      xml.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
    end
  elsif pretty
    to_xml.to_s
  else
    # make sure to not FORMAT it - it breaks signatures!
    to_xml.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML | Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
  end
end

#to_xmlNokogiri::XML::Document

Serialize this object to XML

Returns:

  • (Nokogiri::XML::Document)


71
72
73
74
75
76
77
78
79
80
81
# File 'lib/saml2/base.rb', line 71

def to_xml
  unless instance_variable_defined?(:@document)
    builder = Nokogiri::XML::Builder.new
    build(builder)
    @document = builder.doc
    # if we're re-serializing a parsed document (i.e. after mutating/parsing it),
    # forget the original document we parsed
    @xml = nil
  end
  @document
end