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.



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

def initialize
  @pretty = true
end

Instance Attribute Details

#xmlNokogiri::XML::Element (readonly)

Returns:

  • (Nokogiri::XML::Element)


62
63
64
# File 'lib/saml2/base.rb', line 62

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:



18
19
20
21
22
23
24
# File 'lib/saml2/base.rb', line 18

def from_xml(node)
  return nil unless node

  result = new
  result.from_xml(node)
  result
end

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



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/saml2/base.rb', line 32

def 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



26
27
28
29
30
# File 'lib/saml2/base.rb', line 26

def 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



9
10
11
12
# File 'lib/saml2/base.rb', line 9

def 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.



135
# File 'lib/saml2/base.rb', line 135

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.



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/saml2/base.rb', line 152

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|
      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
  !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)


72
73
74
# File 'lib/saml2/base.rb', line 72

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)


108
109
110
111
112
113
114
# File 'lib/saml2/base.rb', line 108

def inspect
  "#<#{self.class.name} #{instance_variables.filter_map do |iv|
                            next if iv == :@xml

                            "#{iv}=#{instance_variable_get(iv).inspect}"
                          end.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)


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/saml2/base.rb', line 84

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)


119
120
121
122
123
124
125
126
127
128
129
# File 'lib/saml2/base.rb', line 119

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