class SAML2::Message
@abstract
that in this gem as a common base class.
ancestor, but they have several things in common so it’s useful to represent
In the SAML Schema, Request and Response don’t technically share a common
def build(message)
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') if issuer end
def destination
-
(String, nil)-
def destination if xml && !instance_variable_defined?(:@destination) @destination = xml['Destination'] end @destination end
def from_xml(node)
-
(UnknownMessage)- If the element doesn't correspond to a known
Returns:
-
(Message)-
Parameters:
-
node(Nokogiri::XML::Element) --
def from_xml(node) return super unless self == Message klass = Message.known_messages[node.name] raise UnknownMessage.new("Unknown message #{node.name}") unless klass klass.from_xml(node) end
def from_xml(node)
def from_xml(node) super @id = nil @issue_instant = nil end
def id
-
(String)-
def id @id ||= xml['ID'] end
def inherited(klass)
def inherited(klass) # explicitly keep track of all messages in this base class Message.known_messages[klass.name.sub(/^SAML2::/, '')] = klass end
def initialize
def initialize super @errors = [] @id = "_#{SecureRandom.uuid}" @issue_instant = Time.now.utc end
def issue_instant
-
(Time)-
def issue_instant @issue_instant ||= Time.parse(xml['IssueInstant']) end
def issuer
-
(NameID, nil)-
def issuer @issuer ||= NameID.from_xml(xml.at_xpath('saml:Issuer', Namespaces::ALL)) end
def known_messages
def known_messages @known_messages ||= {} end
def parse(xml)
-
(UnexpectedMessage)-
Returns:
-
(Message)-
Parameters:
-
xml(String, IO) -- Anything that can be passed to +Nokogiri::XML+.
def parse(xml) result = Message.from_xml(Nokogiri::XML(xml) { |config| config.strict }.root) raise UnexpectedMessage.new("Expected a #{self.name}, but got a #{result.class.name}") unless self == Message || result.class == self result rescue Nokogiri::XML::SyntaxError raise CorruptMessage end
def sign(x509_certificate, private_key, algorithm_name = :sha256)
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
def valid_schema?
-
(Boolean)-
def valid_schema? return false unless Schemas.protocol.valid?(xml.document) true end
def validate
def validate @errors = Schemas.protocol.validate(xml.document) errors end
def validate_signature(fingerprint: nil,
-
verification_time() --
def validate_signature(fingerprint: nil, cert: nil, verification_time: issue_instant, allow_expired_certificate: false) # verify the signature (certificate's validity) as of the time the message was generated super(fingerprint: fingerprint, cert: cert, verification_time: verification_time, allow_expired_certificate: allow_expired_certificate) end