Class: SAML2::Message

Inherits:
Base
  • Object
show all
Includes:
Signable
Defined in:
lib/saml2/message.rb

Overview

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 here

Direct Known Subclasses

Assertion, Request, StatusResponse

Instance Attribute Summary collapse

Attributes inherited from Base

#xml

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Signable

#signature, #signed?, #signing_key, #valid_signature?

Methods inherited from Base

#inspect, load_object_array, load_string_array, lookup_qname, #to_s, #to_xml

Constructor Details

#initializeMessage

Returns a new instance of Message.



74
75
76
77
78
# File 'lib/saml2/message.rb', line 74

def initialize
  super
  @id = "_#{SecureRandom.uuid}"
  @issue_instant = Time.now.utc
end

Instance Attribute Details

#destinationObject



116
117
118
119
120
121
# File 'lib/saml2/message.rb', line 116

def destination
  if xml && !instance_variable_defined?(:@destination)
    @destination = xml['Destination']
  end
  @destination
end

#issuerObject



123
124
125
# File 'lib/saml2/message.rb', line 123

def issuer
  @issuer ||= NameID.from_xml(xml.at_xpath('saml:Issuer', Namespaces::ALL))
end

Class Method Details

.from_xml(node) ⇒ Object

Raises:



52
53
54
55
56
57
# File 'lib/saml2/message.rb', line 52

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

.inherited(klass) ⇒ Object



47
48
49
50
# File 'lib/saml2/message.rb', line 47

def inherited(klass)
  # explicitly keep track of all messages in this base class
  Message.known_messages[klass.name.sub(/^SAML2::/, '')] = klass
end

.parse(xml) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/saml2/message.rb', line 59

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

Instance Method Details

#from_xml(node) ⇒ Object



80
81
82
83
84
# File 'lib/saml2/message.rb', line 80

def from_xml(node)
  super
  @id = nil
  @issue_instant = nil
end

#idObject



108
109
110
# File 'lib/saml2/message.rb', line 108

def id
  @id ||= xml['ID']
end

#issue_instantObject



112
113
114
# File 'lib/saml2/message.rb', line 112

def issue_instant
  @issue_instant ||= Time.parse(xml['IssueInstant'])
end

#sign(x509_certificate, private_key, algorithm_name = :sha256) ⇒ Object



97
98
99
100
101
102
103
104
105
106
# File 'lib/saml2/message.rb', line 97

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?Boolean

Returns:

  • (Boolean)


86
87
88
89
90
# File 'lib/saml2/message.rb', line 86

def valid_schema?
  return false unless Schemas.protocol.valid?(xml.document)

  true
end

#validate_signature(fingerprint: nil, cert: nil, verification_time: nil) ⇒ Object



92
93
94
95
# File 'lib/saml2/message.rb', line 92

def validate_signature(fingerprint: nil, cert: nil, verification_time: nil)
  # verify the signature (certificate's validity) as of the time the message was generated
  super(fingerprint: fingerprint, cert: cert, verification_time: issue_instant)
end