Class: Onelogin::Saml::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/onelogin/ruby-samlnechotech/response.rb

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Response.

Raises:

  • (ArgumentError)


21
22
23
24
25
26
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 21

def initialize(response, options = {})
  raise ArgumentError.new("Response cannot be nil") if response.nil?
  @options  = options
  @response = (response =~ /^</) ? response : Base64.decode64(response)
  @document = XMLSecurity::SignedDocument.new(@response)
end

Instance Attribute Details

#documentObject (readonly)

Returns the value of attribute document.



19
20
21
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 19

def document
  @document
end

#optionsObject (readonly)

Returns the value of attribute options.



17
18
19
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 17

def options
  @options
end

#responseObject (readonly)

Returns the value of attribute response.



18
19
20
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 18

def response
  @response
end

#settingsObject

TODO: This should probably be ctor initialized too… WDYT?



15
16
17
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 15

def settings
  @settings
end

Instance Method Details

#attributesObject

A hash of alle the attributes with the response. Assuming there is only one value for each key



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 67

def attributes
  @attr_statements ||= begin
    result = {}

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

    stmt_element.elements.each do |attr_element|
      name  = attr_element.attributes["Name"]
      value = attr_element.elements.first.text rescue nil

      result[name] = value
    end

    result.keys.each do |key|
      result[key.intern] = result[key]
    end

    result
  end
end

#conditionsObject

Conditions (if any) for the assertion to run



116
117
118
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 116

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

#is_valid?Boolean

Returns:

  • (Boolean)


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

def is_valid?
  validate
end

#issuerObject



120
121
122
123
124
125
126
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 120

def issuer
  @issuer ||= begin
    node = REXML::XPath.first(document, "/p:Response/a:Issuer", { "p" => PROTOCOL, "a" => ASSERTION })
    node ||= xpath_first_from_signed_assertion('/a:Issuer')
    node.nil? ? nil : node.text
  end
end

#logObject



128
129
130
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 128

def log
  Logging.debug "SAML Response:\n#{document}\n"
end

#name_idObject

The value of the user identifier as designated by the initialization request response



52
53
54
55
56
57
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 52

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

#session_expires_atObject

When this user session should expire at latest



90
91
92
93
94
95
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 90

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

#sessionindexObject



59
60
61
62
63
64
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 59

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

#success?Boolean

Checks the status of the response for a “Success” code (nechotech: …or a “NoPassive” secondary status code)

Returns:

  • (Boolean)


99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 99

def success?
  @status_code ||= begin
    node = REXML::XPath.first(document, "/p:Response/p:Status/p:StatusCode", { "p" => PROTOCOL, "a" => ASSERTION })
    primary_status = node.attributes["Value"]
    case primary_status
      when "urn:oasis:names:tc:SAML:2.0:status:Success"
        true
      when "urn:oasis:names:tc:SAML:2.0:status:Responder"
        secondary_status = node.elements[1].attributes["Value"]
        secondary_status == "urn:oasis:names:tc:SAML:2.0:status:NoPassive"
      else
        false
    end
  end
end

#validate!Object



47
48
49
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 47

def validate!
  validate(false)
end

#xml_cert_validate(idp_cert_fingerprint, logger) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/onelogin/ruby-samlnechotech/response.rb', line 32

def xml_cert_validate(idp_cert_fingerprint, logger)

  # get cert from response
  base64_cert = document.elements["//ds:X509Certificate"].text
  cert_text = Base64.decode64(base64_cert)
  cert = OpenSSL::X509::Certificate.new(cert_text)
  # check cert matches registered idp cert
  fingerprint = Digest::SHA1.hexdigest(cert.to_der)
  valid_flag = fingerprint == idp_cert_fingerprint.gsub(":", "").downcase

  return valid_flag if !valid_flag

  document.validate_doc(base64_cert, Logging)
end