class SAML2::Message

In the SAML Schema, Request and Response don’t technically share a common ancestor, but they have several things in common so it’s useful to represent that in this gem as a common base class. @abstract

Attributes

destination[W]
errors[R]
issuer[W]

Public Class Methods

from_xml(node) click to toggle source

Create an appropriate {Message} subclass instance to represent the given XML element.

When called on a subclass, it behaves the same as {Base.from_xml}

@param node [Nokogiri::XML::Element] @return [Message] @raise [UnknownMessage] If the element doesn’t correspond to a known

SAML message type.
Calls superclass method SAML2::Base::from_xml
# File lib/saml2/message.rb, line 60
def from_xml(node)
  return super unless self == Message

  klass = Message.known_messages[node.name]
  raise UnknownMessage, "Unknown message #{node.name}" unless klass

  klass.from_xml(node)
end
new() click to toggle source
Calls superclass method SAML2::Base::new
# File lib/saml2/message.rb, line 101
def initialize
  super
  @errors = []
  @id = "_#{SecureRandom.uuid}"
  @issue_instant = Time.now.utc
end
parse(xml) click to toggle source

Parses XML, and returns an appropriate {Message} subclass instance.

@param xml [String, IO] Anything that can be passed to Nokogiri::XML. @return [Message] @raise [UnexpectedMessage]

If called on a subclass, will raise if the parsed message does not
match the class is was called on.
# File lib/saml2/message.rb, line 76
def parse(xml)
  result = Message.from_xml(Nokogiri::XML(xml, &:strict).root)
  unless self == Message || result.instance_of?(self)
    raise UnexpectedMessage,
          "Expected a #{name}, but got a #{result.class.name}"
  end

  result
rescue Nokogiri::XML::SyntaxError
  raise CorruptMessage
end

Protected Class Methods

inherited(klass) click to toggle source
Calls superclass method
# File lib/saml2/message.rb, line 94
def inherited(klass)
  super
  # explicitly keep track of all messages in this base class
  Message.known_messages[klass.name.sub(/^SAML2::/, "")] = klass
end
known_messages() click to toggle source
# File lib/saml2/message.rb, line 90
def known_messages
  @known_messages ||= {}
end

Public Instance Methods

destination() click to toggle source

@return [String, nil]

# File lib/saml2/message.rb, line 151
def destination
  @destination = xml["Destination"] if xml && !instance_variable_defined?(:@destination)
  @destination
end
from_xml(node) click to toggle source

(see Base#from_xml)

Calls superclass method SAML2::Base::from_xml
# File lib/saml2/message.rb, line 109
def from_xml(node)
  super
  @id = nil
  @issue_instant = nil
end
id() click to toggle source

@return [String]

# File lib/saml2/message.rb, line 141
def id
  @id ||= xml["ID"]
end
issue_instant() click to toggle source

@return [Time]

# File lib/saml2/message.rb, line 146
def issue_instant
  @issue_instant ||= Time.parse(xml["IssueInstant"])
end
issuer() click to toggle source

@return [NameID, nil]

# File lib/saml2/message.rb, line 157
def issuer
  @issuer ||= NameID.from_xml(xml.at_xpath("saml:Issuer", Namespaces::ALL))
end
sign(x509_certificate, private_key, algorithm_name = :sha256) click to toggle source

(see Signable#sign)

Calls superclass method SAML2::Signable#sign
# File lib/saml2/message.rb, line 129
def sign(x509_certificate, private_key, algorithm_name = :sha256)
  super

  xml = @document.root
  # the Signature element must be right after the Issuer, so put it there
  issuer = xml.at_xpath("saml:Issuer", Namespaces::ALL)
  signature = xml.at_xpath("dsig:Signature", Namespaces::ALL)
  issuer.add_next_sibling(signature)
  self
end
valid_schema?() click to toggle source

If the XML is valid according to SAML XSDs. @return [Boolean]

# File lib/saml2/message.rb, line 122
def valid_schema?
  return false unless Schemas.protocol.valid?(xml.document)

  true
end
validate() click to toggle source
# File lib/saml2/message.rb, line 115
def validate
  @errors = Schemas.protocol.validate(xml.document)
  errors
end

Protected Instance Methods

build(message) click to toggle source

should be called from inside the specific request element

# File lib/saml2/message.rb, line 164
def build(message)
  message.parent["ID"] = id
  message.parent["Version"] = "2.0"
  message.parent["IssueInstant"] = issue_instant.iso8601
  message.parent["Destination"] = destination if destination

  issuer&.build(message, element: "Issuer")
end