Class: OneLogin::RubySaml::Response
- Inherits:
-
SamlMessage
- Object
- SamlMessage
- OneLogin::RubySaml::Response
- Includes:
- ErrorHandling
- 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#"
- AVAILABLE_OPTIONS =
Response available options This is not a whitelist to allow people extending OneLogin::RubySaml:Response and pass custom options
[ :allowed_clock_drift, :check_duplicated_attributes, :matches_request_id, :settings, :skip_audience, :skip_authnstatement, :skip_conditions, :skip_destination, :skip_recipient_check, :skip_subject_confirmation ]
Constants inherited from SamlMessage
Instance Attribute Summary collapse
-
#decrypted_document ⇒ Object
readonly
Returns the value of attribute decrypted_document.
-
#document ⇒ Object
readonly
Returns the value of attribute document.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#response ⇒ Object
readonly
Returns the value of attribute response.
-
#settings ⇒ Object
OneLogin::RubySaml::Settings Toolkit settings.
-
#soft ⇒ Object
Returns the value of attribute soft.
Attributes included from ErrorHandling
Instance Method Summary collapse
-
#allowed_clock_drift ⇒ Float
returns the allowed clock drift on timing validation.
-
#assertion_encrypted? ⇒ Boolean
Checks if the SAML Response contains or not an EncryptedAssertion element.
- #assertion_id ⇒ Object
-
#attributes ⇒ Attributes
Gets the Attributes from the AttributeStatement element.
-
#audiences ⇒ Array
The Audience elements from the Contitions of the SAML Response.
-
#authn_context_class_ref ⇒ String
Gets the AuthnContextClassRef from the AuthnStatement Could be used to require re-authentication if the assertion did not met the requested authentication context class.
-
#authn_instant ⇒ String
Gets the AuthnInstant from the AuthnStatement.
-
#conditions ⇒ REXML::Element
Gets the Condition Element of the SAML Response if exists.
-
#destination ⇒ String|nil
Destination attribute from the SAML Response.
-
#in_response_to ⇒ String|nil
The InResponseTo attribute from the SAML Response.
-
#initialize(response, options = {}) ⇒ Response
constructor
Constructs the SAML Response.
-
#is_valid?(collect_errors = false) ⇒ Boolean
Validates the SAML Response with the default values (soft = true).
-
#issuers ⇒ Array
Gets the Issuers (from Response and Assertion).
-
#name_id ⇒ String
(also: #nameid)
The NameID provided by the SAML response from the IdP.
-
#name_id_format ⇒ String
(also: #nameid_format)
The NameID Format provided by the SAML response from the IdP.
-
#name_id_namequalifier ⇒ String
The NameID NameQualifier provided by the SAML response from the IdP.
-
#name_id_spnamequalifier ⇒ String
The NameID SPNameQualifier provided by the SAML response from the IdP.
-
#not_before ⇒ Time
Gets the NotBefore Condition Element value.
-
#not_on_or_after ⇒ Time
Gets the NotOnOrAfter Condition Element value.
- #response_id ⇒ Object
-
#session_expires_at ⇒ String
Gets the SessionNotOnOrAfter from the AuthnStatement.
-
#sessionindex ⇒ String
Gets the SessionIndex from the AuthnStatement.
-
#status_code ⇒ String
StatusCode value from a SAML Response.
-
#status_message ⇒ String
The StatusMessage value from a SAML Response.
-
#success? ⇒ Boolean
Checks if the Status has the “Success” code.
Methods included from ErrorHandling
Methods inherited from SamlMessage
#id, schema, #valid_saml?, #version
Constructor Details
#initialize(response, options = {}) ⇒ Response
Constructs the SAML Response. A Response Object that is an extension of the SamlMessage class.
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/onelogin/ruby-saml/response.rb', line 52 def initialize(response, = {}) raise ArgumentError.new("Response cannot be nil") if response.nil? @errors = [] @options = @soft = true unless [:settings].nil? @settings = [:settings] unless @settings.soft.nil? @soft = @settings.soft end end @response = decode_raw_saml(response, settings) @document = XMLSecurity::SignedDocument.new(@response, @errors) if assertion_encrypted? @decrypted_document = generate_decrypted_document end end |
Instance Attribute Details
#decrypted_document ⇒ Object (readonly)
Returns the value of attribute decrypted_document.
27 28 29 |
# File 'lib/onelogin/ruby-saml/response.rb', line 27 def decrypted_document @decrypted_document end |
#document ⇒ Object (readonly)
Returns the value of attribute document.
26 27 28 |
# File 'lib/onelogin/ruby-saml/response.rb', line 26 def document @document end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
29 30 31 |
# File 'lib/onelogin/ruby-saml/response.rb', line 29 def @options end |
#response ⇒ Object (readonly)
Returns the value of attribute response.
28 29 30 |
# File 'lib/onelogin/ruby-saml/response.rb', line 28 def response @response end |
#settings ⇒ Object
OneLogin::RubySaml::Settings Toolkit settings
24 25 26 |
# File 'lib/onelogin/ruby-saml/response.rb', line 24 def settings @settings end |
#soft ⇒ Object
Returns the value of attribute soft.
31 32 33 |
# File 'lib/onelogin/ruby-saml/response.rb', line 31 def soft @soft end |
Instance Method Details
#allowed_clock_drift ⇒ Float
returns the allowed clock drift on timing validation
362 363 364 |
# File 'lib/onelogin/ruby-saml/response.rb', line 362 def allowed_clock_drift [:allowed_clock_drift].to_f.abs + Float::EPSILON end |
#assertion_encrypted? ⇒ Boolean
Checks if the SAML Response contains or not an EncryptedAssertion element
369 370 371 372 373 374 375 |
# File 'lib/onelogin/ruby-saml/response.rb', line 369 def assertion_encrypted? ! REXML::XPath.first( document, "(/p:Response/EncryptedAssertion/)|(/p:Response/a:EncryptedAssertion/)", { "p" => PROTOCOL, "a" => ASSERTION } ).nil? end |
#assertion_id ⇒ Object
381 382 383 384 385 386 |
# File 'lib/onelogin/ruby-saml/response.rb', line 381 def assertion_id @assertion_id ||= begin node = xpath_first_from_signed_assertion("") node.nil? ? nil : node.attributes['ID'] end end |
#attributes ⇒ Attributes
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']
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/onelogin/ruby-saml/response.rb', line 147 def attributes @attr_statements ||= begin attributes = Attributes.new stmt_elements = xpath_from_signed_assertion('/a:AttributeStatement') stmt_elements.each do |stmt_element| stmt_element.elements.each do |attr_element| if attr_element.name == "EncryptedAttribute" node = decrypt_attribute(attr_element.dup) else node = attr_element end name = node.attributes["Name"] if [:check_duplicated_attributes] && attributes.include?(name) raise ValidationError.new("Found an Attribute element with duplicated Name") end values = node.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 : Utils.element_text(e) # 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 do |n| base_path = n.attributes['NameQualifier'] ? "#{n.attributes['NameQualifier']}/" : '' "#{base_path}#{Utils.element_text(n)}" end end } attributes.add(name, values.flatten) end end attributes end end |
#audiences ⇒ Array
Returns The Audience elements from the Contitions of the SAML Response.
353 354 355 356 357 358 |
# File 'lib/onelogin/ruby-saml/response.rb', line 353 def audiences @audiences ||= begin nodes = xpath_from_signed_assertion('/a:Conditions/a:AudienceRestriction/a:Audience') nodes.map { |node| Utils.element_text(node) }.reject(&:empty?) end end |
#authn_context_class_ref ⇒ String
Gets the AuthnContextClassRef from the AuthnStatement Could be used to require re-authentication if the assertion did not met the requested authentication context class.
218 219 220 |
# File 'lib/onelogin/ruby-saml/response.rb', line 218 def authn_context_class_ref @authn_context_class_ref ||= Utils.element_text(xpath_first_from_signed_assertion('/a:AuthnStatement/a:AuthnContext/a:AuthnContextClassRef')) end |
#authn_instant ⇒ String
Gets the AuthnInstant from the AuthnStatement. Could be used to require re-authentication if a long time has passed since the last user authentication.
206 207 208 209 210 211 |
# File 'lib/onelogin/ruby-saml/response.rb', line 206 def authn_instant @authn_instant ||= begin node = xpath_first_from_signed_assertion('/a:AuthnStatement') node.nil? ? nil : node.attributes['AuthnInstant'] end end |
#conditions ⇒ REXML::Element
Gets the Condition Element of the SAML Response if exists. (returns the first node that matches the supplied xpath)
279 280 281 |
# File 'lib/onelogin/ruby-saml/response.rb', line 279 def conditions @conditions ||= xpath_first_from_signed_assertion('/a:Conditions') end |
#destination ⇒ String|nil
Returns Destination attribute from the SAML Response.
340 341 342 343 344 345 346 347 348 349 |
# File 'lib/onelogin/ruby-saml/response.rb', line 340 def destination @destination ||= begin node = REXML::XPath.first( document, "/p:Response", { "p" => PROTOCOL } ) node.nil? ? nil : node.attributes['Destination'] end end |
#in_response_to ⇒ String|nil
Returns The InResponseTo attribute from the SAML Response.
327 328 329 330 331 332 333 334 335 336 |
# File 'lib/onelogin/ruby-saml/response.rb', line 327 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?(collect_errors = false) ⇒ Boolean
Validates the SAML Response with the default values (soft = true)
78 79 80 |
# File 'lib/onelogin/ruby-saml/response.rb', line 78 def is_valid?(collect_errors = false) validate(collect_errors) end |
#issuers ⇒ Array
Gets the Issuers (from Response and Assertion). (returns the first node that matches the supplied xpath from the Response and from the Assertion)
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/onelogin/ruby-saml/response.rb', line 301 def issuers @issuers ||= begin issuer_response_nodes = REXML::XPath.match( document, "/p:Response/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION } ) unless issuer_response_nodes.size == 1 error_msg = "Issuer of the Response not found or multiple." raise ValidationError.new(error_msg) end issuer_assertion_nodes = xpath_from_signed_assertion("/a:Issuer") unless issuer_assertion_nodes.size == 1 error_msg = "Issuer of the Assertion not found or multiple." raise ValidationError.new(error_msg) end nodes = issuer_response_nodes + issuer_assertion_nodes nodes.map { |node| Utils.element_text(node) }.compact.uniq end end |
#name_id ⇒ String Also known as: nameid
Returns the NameID provided by the SAML response from the IdP.
84 85 86 |
# File 'lib/onelogin/ruby-saml/response.rb', line 84 def name_id @name_id ||= Utils.element_text(name_id_node) end |
#name_id_format ⇒ String Also known as: nameid_format
Returns the NameID Format provided by the SAML response from the IdP.
92 93 94 95 96 97 |
# File 'lib/onelogin/ruby-saml/response.rb', line 92 def name_id_format @name_id_format ||= if name_id_node && name_id_node.attribute("Format") name_id_node.attribute("Format").value end end |
#name_id_namequalifier ⇒ String
Returns the NameID NameQualifier provided by the SAML response from the IdP.
112 113 114 115 116 117 |
# File 'lib/onelogin/ruby-saml/response.rb', line 112 def name_id_namequalifier @name_id_namequalifier ||= if name_id_node && name_id_node.attribute("NameQualifier") name_id_node.attribute("NameQualifier").value end end |
#name_id_spnamequalifier ⇒ String
Returns the NameID SPNameQualifier provided by the SAML response from the IdP.
103 104 105 106 107 108 |
# File 'lib/onelogin/ruby-saml/response.rb', line 103 def name_id_spnamequalifier @name_id_spnamequalifier ||= if name_id_node && name_id_node.attribute("SPNameQualifier") name_id_node.attribute("SPNameQualifier").value end end |
#not_before ⇒ Time
Gets the NotBefore Condition Element value.
286 287 288 |
# File 'lib/onelogin/ruby-saml/response.rb', line 286 def not_before @not_before ||= parse_time(conditions, "NotBefore") end |
#not_on_or_after ⇒ Time
Gets the NotOnOrAfter Condition Element value.
293 294 295 |
# File 'lib/onelogin/ruby-saml/response.rb', line 293 def not_on_or_after @not_on_or_after ||= parse_time(conditions, "NotOnOrAfter") end |
#response_id ⇒ Object
377 378 379 |
# File 'lib/onelogin/ruby-saml/response.rb', line 377 def response_id id(document) end |
#session_expires_at ⇒ String
Gets the SessionNotOnOrAfter from the AuthnStatement. Could be used to set the local session expiration (expire at latest)
194 195 196 197 198 199 |
# File 'lib/onelogin/ruby-saml/response.rb', line 194 def session_expires_at @expires_at ||= begin node = xpath_first_from_signed_assertion('/a:AuthnStatement') node.nil? ? nil : parse_time(node, "SessionNotOnOrAfter") end end |
#sessionindex ⇒ String
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
125 126 127 128 129 130 |
# File 'lib/onelogin/ruby-saml/response.rb', line 125 def sessionindex @sessionindex ||= begin node = xpath_first_from_signed_assertion('/a:AuthnStatement') node.nil? ? nil : node.attributes['SessionIndex'] end end |
#status_code ⇒ String
Returns StatusCode value from a SAML Response.
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/onelogin/ruby-saml/response.rb', line 231 def status_code @status_code ||= begin nodes = REXML::XPath.match( document, "/p:Response/p:Status/p:StatusCode", { "p" => PROTOCOL } ) if nodes.size == 1 node = nodes[0] code = node.attributes["Value"] if node && node.attributes unless code == "urn:oasis:names:tc:SAML:2.0:status:Success" nodes = REXML::XPath.match( document, "/p:Response/p:Status/p:StatusCode/p:StatusCode", { "p" => PROTOCOL } ) statuses = nodes.collect do |inner_node| inner_node.attributes["Value"] end code = [code, statuses].flatten.join(" | ") end code end end end |
#status_message ⇒ String
Returns the StatusMessage value from a SAML Response.
262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/onelogin/ruby-saml/response.rb', line 262 def @status_message ||= begin nodes = REXML::XPath.match( document, "/p:Response/p:Status/p:StatusMessage", { "p" => PROTOCOL } ) if nodes.size == 1 Utils.element_text(nodes.first) end end end |
#success? ⇒ Boolean
Checks if the Status has the “Success” code
225 226 227 |
# File 'lib/onelogin/ruby-saml/response.rb', line 225 def success? status_code == "urn:oasis:names:tc:SAML:2.0:status:Success" end |