Class: OneLogin::RubySaml::Response

Inherits:
SamlMessage show all
Defined in:
lib/onelogin/ruby-saml/response.rb

Overview

SAML2 Authentication Response. SAML Response

Constant Summary collapse

ASSERTION =
"urn:oasis:names:tc:SAML:2.0:assertion"
PROTOCOL =
"urn:oasis:names:tc:SAML:2.0:protocol"
DSIG =
"http://www.w3.org/2000/09/xmldsig#"
XENC =
"http://www.w3.org/2001/04/xmlenc#"

Constants inherited from SamlMessage

SamlMessage::BASE64_FORMAT

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from SamlMessage

#id, schema, #valid_saml?, #validation_error, #version

Constructor Details

#initialize(response, options = {}) ⇒ Response

Constructs the SAML Response. A Response Object that is an extension of the SamlMessage class.

Parameters:

  • response (String)

    A UUEncoded SAML response from the IdP.

  • options (Hash) (defaults to: {})

    :settings to provide the OneLogin::RubySaml::Settings object Or some options for the response validation process like skip the conditions validation with the :skip_conditions, or allow a clock_drift when checking dates with :allowed_clock_drift or :matches_request_id that will validate that the response matches the ID of the request, or skip the subject confirmation validation with the :skip_subject_confirmation option

Raises:

  • (ArgumentError)


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/onelogin/ruby-saml/response.rb', line 41

def initialize(response, options = {})
  @errors = []

  raise ArgumentError.new("Response cannot be nil") if response.nil?
  @options = options

  @soft = true
  if !options.empty? && !options[:settings].nil?
    @settings = options[:settings]
    if !options[:settings].soft.nil? 
      @soft = options[:settings].soft
    end
  end

  @response = decode_raw_saml(response)
  @document = XMLSecurity::SignedDocument.new(@response, @errors)

  if assertion_encrypted?
    @decrypted_document = generate_decrypted_document
  end
end

Instance Attribute Details

#decrypted_documentObject (readonly)

Returns the value of attribute decrypted_document.



28
29
30
# File 'lib/onelogin/ruby-saml/response.rb', line 28

def decrypted_document
  @decrypted_document
end

#documentObject (readonly)

Returns the value of attribute document.



27
28
29
# File 'lib/onelogin/ruby-saml/response.rb', line 27

def document
  @document
end

#errorsObject

Array with the causes [Array of strings]



25
26
27
# File 'lib/onelogin/ruby-saml/response.rb', line 25

def errors
  @errors
end

#optionsObject (readonly)

Returns the value of attribute options.



30
31
32
# File 'lib/onelogin/ruby-saml/response.rb', line 30

def options
  @options
end

#responseObject (readonly)

Returns the value of attribute response.



29
30
31
# File 'lib/onelogin/ruby-saml/response.rb', line 29

def response
  @response
end

#settingsObject

OneLogin::RubySaml::Settings Toolkit settings



22
23
24
# File 'lib/onelogin/ruby-saml/response.rb', line 22

def settings
  @settings
end

#softObject

Returns the value of attribute soft.



32
33
34
# File 'lib/onelogin/ruby-saml/response.rb', line 32

def soft
  @soft
end

Instance Method Details

#allowed_clock_driftInteger

returns the allowed clock drift on timing validation

Returns:

  • (Integer)


274
275
276
# File 'lib/onelogin/ruby-saml/response.rb', line 274

def allowed_clock_drift
  return options[:allowed_clock_drift] || 0
end

#append_error(error_msg) ⇒ Object

Append the cause to the errors array, and based on the value of soft, return false or raise an exception



65
66
67
68
# File 'lib/onelogin/ruby-saml/response.rb', line 65

def append_error(error_msg)
  @errors << error_msg
  return soft ? false : validation_error(error_msg)
end

#attributesAttributes

Gets the Attributes from the AttributeStatement element.

All attributes can be iterated over attributes.each or returned as array by attributes.all For backwards compatibility ruby-saml returns by default only the first value for a given attribute with

attributes['name']

To get all of the attributes, use:

attributes.multi('name')

Or turn off the compatibility:

OneLogin::RubySaml::Attributes.single_value_compatibility = false

Now this will return an array:

attributes['name']

Returns:

  • (Attributes)

    OneLogin::RubySaml::Attributes enumerable collection.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/onelogin/ruby-saml/response.rb', line 126

def attributes
  @attr_statements ||= begin
    attributes = Attributes.new

    stmt_element = xpath_first_from_signed_assertion('/a:AttributeStatement')
    return attributes if stmt_element.nil?

    stmt_element.elements.each do |attr_element|
      name  = attr_element.attributes["Name"]
      values = attr_element.elements.collect{|e|
        if (e.elements.nil? || e.elements.size == 0)
          # SAMLCore requires that nil AttributeValues MUST contain xsi:nil XML attribute set to "true" or "1"
          # otherwise the value is to be regarded as empty.
          ["true", "1"].include?(e.attributes['xsi:nil']) ? nil : e.text.to_s
        # explicitly support saml2:NameID with saml2:NameQualifier if supplied in attributes
        # this is useful for allowing eduPersonTargetedId to be passed as an opaque identifier to use to 
        # identify the subject in an SP rather than email or other less opaque attributes
        # NameQualifier, if present is prefixed with a "/" to the value
        else 
         REXML::XPath.match(e,'a:NameID', { "a" => ASSERTION }).collect{|n|
            (n.attributes['NameQualifier'] ? n.attributes['NameQualifier'] +"/" : '') + n.text.to_s
          }
        end
      }

      attributes.add(name, values.flatten)
    end

    attributes
  end
end

#audiencesArray

Returns The Audience elements from the Contitions of the SAML Response.

Returns:

  • (Array)

    The Audience elements from the Contitions of the SAML Response.



259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/onelogin/ruby-saml/response.rb', line 259

def audiences
  @audiences ||= begin
    audiences = []
    nodes = xpath_from_signed_assertion('/a:Conditions/a:AudienceRestriction/a:Audience')
    nodes.each do |node|
      if node && node.text
        audiences << node.text
      end
    end
    audiences
  end
end

#conditionsREXML::Element

Gets the Condition Element of the SAML Response if exists. (returns the first node that matches the supplied xpath)

Returns:

  • (REXML::Element)

    Conditions Element if exists



206
207
208
# File 'lib/onelogin/ruby-saml/response.rb', line 206

def conditions
  @conditions ||= xpath_first_from_signed_assertion('/a:Conditions')
end

#in_response_toString|nil

Returns The InResponseTo attribute from the SAML Response.

Returns:

  • (String|nil)

    The InResponseTo attribute from the SAML Response.



246
247
248
249
250
251
252
253
254
255
# File 'lib/onelogin/ruby-saml/response.rb', line 246

def in_response_to
  @in_response_to ||= begin
    node = REXML::XPath.first(
      document,
      "/p:Response",
      { "p" => PROTOCOL }
    )
    node.nil? ? nil : node.attributes['InResponseTo']
  end
end

#is_valid?Boolean

Validates the SAML Response with the default values (soft = true)

Returns:

  • (Boolean)

    TRUE if the SAML Response is valid



78
79
80
# File 'lib/onelogin/ruby-saml/response.rb', line 78

def is_valid?
  validate
end

#issuersArray

Gets the Issuers (from Response and Assertion). (returns the first node that matches the supplied xpath from the Response and from the Assertion)

Returns:

  • (Array)

    Array with the Issuers (REXML::Element)



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/onelogin/ruby-saml/response.rb', line 228

def issuers
  @issuers ||= begin
    issuers = []
    nodes = REXML::XPath.match(
      document,
      "/p:Response/a:Issuer",
      { "p" => PROTOCOL, "a" => ASSERTION }
    )
    nodes += xpath_from_signed_assertion("/a:Issuer")
    nodes.each do |node|
      issuers << node.text if node.text
    end
    issuers.uniq
  end
end

#name_idString Also known as: nameid

Returns the NameID provided by the SAML response from the IdP.

Returns:

  • (String)

    the NameID provided by the SAML response from the IdP.



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/onelogin/ruby-saml/response.rb', line 84

def name_id
  @name_id ||= begin
    encrypted_node = xpath_first_from_signed_assertion('/a:Subject/a:EncryptedID')
    if encrypted_node
      node = decrypt_nameid(encrypted_node)
    else
      node = xpath_first_from_signed_assertion('/a:Subject/a:NameID')
    end
    node.nil? ? nil : node.text
  end
end

#not_beforeTime

Gets the NotBefore Condition Element value.

Returns:

  • (Time)

    The NotBefore value in Time format



213
214
215
# File 'lib/onelogin/ruby-saml/response.rb', line 213

def not_before
  @not_before ||= parse_time(conditions, "NotBefore")
end

#not_on_or_afterTime

Gets the NotOnOrAfter Condition Element value.

Returns:

  • (Time)

    The NotOnOrAfter value in Time format



220
221
222
# File 'lib/onelogin/ruby-saml/response.rb', line 220

def not_on_or_after
  @not_on_or_after ||= parse_time(conditions, "NotOnOrAfter")
end

#reset_errors!Object

Reset the errors array



71
72
73
# File 'lib/onelogin/ruby-saml/response.rb', line 71

def reset_errors!
  @errors = []
end

#session_expires_atString

Gets the SessionNotOnOrAfter from the AuthnStatement. Could be used to set the local session expiration (expire at latest)

Returns:

  • (String)

    The SessionNotOnOrAfter value



162
163
164
165
166
167
# File 'lib/onelogin/ruby-saml/response.rb', line 162

def session_expires_at
  @expires_at ||= begin
    node = xpath_first_from_signed_assertion('/a:AuthnStatement')
    node.nil? ? nil : parse_time(node, "SessionNotOnOrAfter")
  end
end

#sessionindexString

Gets the SessionIndex from the AuthnStatement. Could be used to be stored in the local session in order to be used in a future Logout Request that the SP could send to the IdP, to set what specific session must be deleted

Returns:

  • (String)

    SessionIndex Value



105
106
107
108
109
110
# File 'lib/onelogin/ruby-saml/response.rb', line 105

def sessionindex
  @sessionindex ||= begin
    node = xpath_first_from_signed_assertion('/a:AuthnStatement')
    node.nil? ? nil : node.attributes['SessionIndex']
  end
end

#status_codeString

Returns StatusCode value from a SAML Response.

Returns:

  • (String)

    StatusCode value from a SAML Response.



178
179
180
181
182
183
184
185
186
187
# File 'lib/onelogin/ruby-saml/response.rb', line 178

def status_code
  @status_code ||= begin
    node = REXML::XPath.first(
      document,
      "/p:Response/p:Status/p:StatusCode",
      { "p" => PROTOCOL, "a" => ASSERTION }
    )
    node.attributes["Value"] if node && node.attributes
  end
end

#status_messageString

Returns the StatusMessage value from a SAML Response.

Returns:

  • (String)

    the StatusMessage value from a SAML Response.



191
192
193
194
195
196
197
198
199
200
# File 'lib/onelogin/ruby-saml/response.rb', line 191

def status_message
  @status_message ||= begin
    node = REXML::XPath.first(
      document,
      "/p:Response/p:Status/p:StatusMessage",
      { "p" => PROTOCOL, "a" => ASSERTION }
    )
    node.text if node
  end
end

#success?Boolean

Checks if the Status has the “Success” code

Returns:

  • (Boolean)

    True if the StatusCode is Sucess



172
173
174
# File 'lib/onelogin/ruby-saml/response.rb', line 172

def success?
  status_code == "urn:oasis:names:tc:SAML:2.0:status:Success"
end