Class: OneLogin::KlRubySaml::Response

Inherits:
SamlMessage show all
Defined in:
lib/onelogin/kl-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::KlRubySaml::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.

Raises:

  • (ArgumentError)


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

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 = KlXMLSecurity::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/kl-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/kl-ruby-saml/response.rb', line 27

def document
  @document
end

#errorsObject

Array with the causes [Array of strings]



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

def errors
  @errors
end

#optionsObject (readonly)

Returns the value of attribute options.



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

def options
  @options
end

#responseObject (readonly)

Returns the value of attribute response.



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

def response
  @response
end

#settingsObject

OneLogin::KlRubySaml::Settings Toolkit settings



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

def settings
  @settings
end

#softObject

Returns the value of attribute soft.



32
33
34
# File 'lib/onelogin/kl-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)


262
263
264
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 262

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



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

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 kl-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::KlRubySaml::Attributes.single_value_compatibility = false

Now this will return an array:

attributes['name']

Returns:

  • (Attributes)

    OneLogin::KlRubySaml::Attributes enumerable collection.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 124

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|
        # 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
      }

      attributes.add(name, values)
    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.



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

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



194
195
196
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 194

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.



234
235
236
237
238
239
240
241
242
243
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 234

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



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

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)



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 216

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.



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

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



201
202
203
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 201

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



208
209
210
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 208

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

#reset_errors!Object

Reset the errors array



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

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



150
151
152
153
154
155
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 150

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



103
104
105
106
107
108
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 103

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.



166
167
168
169
170
171
172
173
174
175
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 166

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.



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

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



160
161
162
# File 'lib/onelogin/kl-ruby-saml/response.rb', line 160

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