ruby-saml-mod 0.1.25 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: 5884860b076f35e491df0c3d402a03d60da78778
4
+ data.tar.gz: f4ef94c69230b9799cbae69c2ba6cb5b21a9ef95
5
+ !binary "U0hBNTEy":
6
+ metadata.gz: 2284ac2e714c3bc981de6ac2e2a87b9da238f6f7053561eab6fa30724d36eff99a43590c5d191b329fe064ca02b2540352e732569bfd67e72d1f586624f92049
7
+ data.tar.gz: 000451843ab8775c51367a6d409f1c763e2fd4cd1cb6fb3d04a8e77de07ce93ce611279dd7b1e4594f176f74336a9c8b7cf943f7e55227fecacfee5906f0c241
@@ -30,7 +30,7 @@ module Onelogin::Saml
30
30
  @request_xml += "</samlp:AuthnRequest>"
31
31
 
32
32
  deflated_request = Zlib::Deflate.deflate(@request_xml, 9)[2..-5]
33
- base64_request = Base64.strict_encode64(deflated_request)
33
+ base64_request = Base64.encode64(deflated_request)
34
34
  encoded_request = CGI.escape(base64_request)
35
35
 
36
36
  @forward_url = @settings.idp_sso_target_url + (@settings.idp_sso_target_url.include?("?") ? "&" : "?") + "SAMLRequest=" + encoded_request
@@ -11,11 +11,11 @@ module Onelogin::Saml
11
11
  ar = LogOutRequest.new(settings, session)
12
12
  ar.generate_request
13
13
  end
14
-
14
+
15
15
  def generate_request
16
16
  @id = Onelogin::Saml::AuthRequest.generate_unique_id(42)
17
17
  issue_instant = Onelogin::Saml::AuthRequest.get_timestamp
18
-
18
+
19
19
  @request_xml = <<-REQUEST_XML
20
20
  <samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="#{@id}" Version="2.0" IssueInstant="#{issue_instant}" Destination="#{@settings.idp_slo_target_url}">
21
21
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">#{@settings.issuer}</saml:Issuer>
@@ -24,12 +24,8 @@ module Onelogin::Saml
24
24
  </samlp:LogoutRequest>
25
25
  REQUEST_XML
26
26
 
27
- if settings.sign?
28
- @request_xml = XMLSecurity.sign(@id, @request_xml, @settings.xmlsec_privatekey, @settings.xmlsec_certificate)
29
- end
30
-
31
27
  deflated_logout_request = Zlib::Deflate.deflate(@request_xml, 9)[2..-5]
32
- base64_logout_request = Base64.strict_encode64(deflated_logout_request)
28
+ base64_logout_request = Base64.encode64(deflated_logout_request)
33
29
 
34
30
  url, existing_query_string = @settings.idp_slo_target_url.split('?')
35
31
  query_string = _query_string_append(existing_query_string, 'SAMLRequest', base64_logout_request)
@@ -41,7 +37,7 @@ module Onelogin::Saml
41
37
  end
42
38
 
43
39
  @forward_url = [url, query_string].join("?")
44
-
40
+
45
41
  @forward_url
46
42
  end
47
43
 
@@ -2,7 +2,7 @@ module Onelogin::Saml
2
2
  class Response
3
3
 
4
4
  attr_accessor :settings
5
- attr_reader :document, :xml, :response
5
+ attr_reader :document, :decrypted_document, :xml, :response
6
6
  attr_reader :name_id, :name_qualifier, :session_index, :saml_attributes
7
7
  attr_reader :status_code, :status_message
8
8
  attr_reader :in_response_to, :destination, :issuer
@@ -14,14 +14,14 @@ module Onelogin::Saml
14
14
  @xml = Base64.decode64(@response)
15
15
  @document = LibXML::XML::Document.string(@xml)
16
16
  @document.extend(XMLSecurity::SignedDocument)
17
- rescue
17
+ rescue => e
18
18
  # could not parse document, everything is invalid
19
19
  @response = nil
20
20
  return
21
21
  end
22
22
 
23
- @issuer = document.find_first("/samlp:Response/saml:Issuer", Onelogin::NAMESPACES).content rescue nil
24
- @status_code = document.find_first("/samlp:Response/samlp:Status/samlp:StatusCode", Onelogin::NAMESPACES)["Value"] rescue nil
23
+ @issuer = @document.find_first("/samlp:Response/saml:Issuer", Onelogin::NAMESPACES).content rescue nil
24
+ @status_code = @document.find_first("/samlp:Response/samlp:Status/samlp:StatusCode", Onelogin::NAMESPACES)["Value"] rescue nil
25
25
 
26
26
  process(settings) if settings
27
27
  end
@@ -30,119 +30,79 @@ module Onelogin::Saml
30
30
  @settings = settings
31
31
  return unless @response
32
32
 
33
- @in_response_to = untrusted_find_first("/samlp:Response")['InResponseTo'] rescue nil
34
- @destination = untrusted_find_first("/samlp:Response")['Destination'] rescue nil
35
- @status_message = untrusted_find_first("/samlp:Response/samlp:Status/samlp:StatusCode").content rescue nil
36
-
37
- @name_id = trusted_find_first("saml:Assertion/saml:Subject/saml:NameID").content rescue nil
38
- @name_qualifier = trusted_find_first("saml:Assertion/saml:Subject/saml:NameID")["NameQualifier"] rescue nil
39
- @session_index = trusted_find_first("saml:Assertion/saml:AuthnStatement")["SessionIndex"] rescue nil
33
+ @decrypted_document = LibXML::XML::Document.document(@document)
34
+ @decrypted_document.extend(XMLSecurity::SignedDocument)
35
+ @decrypted_document.decrypt!(@settings)
40
36
 
37
+ @in_response_to = @decrypted_document.find_first("/samlp:Response", Onelogin::NAMESPACES)['InResponseTo'] rescue nil
38
+ @destination = @decrypted_document.find_first("/samlp:Response", Onelogin::NAMESPACES)['Destination'] rescue nil
39
+ @name_id = @decrypted_document.find_first("/samlp:Response/saml:Assertion/saml:Subject/saml:NameID", Onelogin::NAMESPACES).content rescue nil
41
40
  @saml_attributes = {}
42
- trusted_find("saml:Attribute").each do |attr|
41
+ @decrypted_document.find("//saml:Attribute", Onelogin::NAMESPACES).each do |attr|
43
42
  attrname = attr['FriendlyName'] || Onelogin::ATTRIBUTES[attr['Name']] || attr['Name']
44
43
  @saml_attributes[attrname] = attr.content.strip rescue nil
45
44
  end
46
- end
47
-
48
- def disable_signature_validation!(settings)
49
- @settings = settings
50
- @is_valid = true
51
- @trusted_roots = [decrypted_document.root]
52
- end
53
-
54
- def decrypted_document
55
- @decrypted_document ||= LibXML::XML::Document.document(document).tap do |doc|
56
- doc.extend(XMLSecurity::SignedDocument)
57
- doc.decrypt!(settings)
58
- end
59
- end
60
-
61
- def untrusted_find_first(xpath)
62
- decrypted_document.find(xpath, Onelogin::NAMESPACES).first
63
- end
64
-
65
- def trusted_find_first(xpath)
66
- trusted_find(xpath).first
67
- end
68
-
69
- def trusted_find(xpath)
70
- trusted_roots.map do |trusted_root|
71
- trusted_root.find("descendant-or-self::#{xpath}", Onelogin::NAMESPACES).to_a
72
- end.flatten.compact
45
+ @name_qualifier = @decrypted_document.find_first("/samlp:Response/saml:Assertion/saml:Subject/saml:NameID", Onelogin::NAMESPACES)["NameQualifier"] rescue nil
46
+ @session_index = @decrypted_document.find_first("/samlp:Response/saml:Assertion/saml:AuthnStatement", Onelogin::NAMESPACES)["SessionIndex"] rescue nil
47
+ @status_message = @decrypted_document.find_first("/samlp:Response/samlp:Status/samlp:StatusCode", Onelogin::NAMESPACES).content rescue nil
73
48
  end
74
49
 
75
50
  def logger=(val)
76
51
  @logger = val
77
52
  end
78
-
53
+
79
54
  def is_valid?
80
- @is_valid ||= validate
81
- end
82
-
83
- def validate
84
- if response.nil? || response == ""
55
+ if @response.nil? || @response == ""
85
56
  @validation_error = "No response to validate"
86
57
  return false
87
58
  end
88
-
89
- if !settings.idp_cert_fingerprint
59
+
60
+ if !@settings.idp_cert_fingerprint
90
61
  @validation_error = "No fingerprint configured in SAML settings"
91
62
  return false
92
63
  end
93
-
64
+
94
65
  # Verify the original document if it has a signature, otherwise verify the signature
95
66
  # in the encrypted portion. If there is no signature, then we can't verify.
96
67
  verified = false
97
-
98
- if document.has_signature?
99
- verified = document.validate(settings.idp_cert_fingerprint, @logger)
68
+ if @document.find_first("//ds:Signature", Onelogin::NAMESPACES)
69
+ verified = @document.validate(@settings.idp_cert_fingerprint, @logger)
100
70
  if !verified
101
- @validation_error = document.validation_error
71
+ @validation_error = @document.validation_error
102
72
  return false
103
73
  end
104
74
  end
105
75
 
106
- if !verified && decrypted_document.has_signature?
107
- verified = decrypted_document.validate(settings.idp_cert_fingerprint, @logger)
76
+ if !verified && @decrypted_document.find_first("//ds:Signature", Onelogin::NAMESPACES)
77
+ verified = @decrypted_document.validate(@settings.idp_cert_fingerprint, @logger)
108
78
  if !verified
109
- @validation_error = decrypted_document.validation_error
79
+ @validation_error = @document.validation_error
110
80
  return false
111
81
  end
112
82
  end
113
-
83
+
114
84
  if !verified
115
85
  @validation_error = "No signature found in the response"
116
86
  return false
117
87
  end
118
-
119
- # If we get here, validation has succeeded, and we can trust all
120
- # <ds:Signature> elements. Each of those has a <ds:Reference> which
121
- # points to the root of the root of the NodeSet it signs.
122
- @trusted_roots = decrypted_document.signed_roots
123
-
88
+
124
89
  true
125
90
  end
126
-
127
- # triggers validation
128
- def trusted_roots
129
- is_valid? ? @trusted_roots : []
130
- end
131
-
91
+
132
92
  def success_status?
133
93
  @status_code == Onelogin::Saml::StatusCodes::SUCCESS_URI
134
94
  end
135
-
95
+
136
96
  def auth_failure?
137
97
  @status_code == Onelogin::Saml::StatusCodes::AUTHN_FAILED_URI
138
98
  end
139
-
99
+
140
100
  def no_authn_context?
141
101
  @status_code == Onelogin::Saml::StatusCodes::NO_AUTHN_CONTEXT_URI
142
102
  end
143
-
103
+
144
104
  def fingerprint_from_idp
145
- if base64_cert = decrypted_document.find_first("//ds:X509Certificate", Onelogin::NAMESPACES)
105
+ if base64_cert = @decrypted_document.find_first("//ds:X509Certificate", Onelogin::NAMESPACES)
146
106
  cert_text = Base64.decode64(base64_cert.content)
147
107
  cert = OpenSSL::X509::Certificate.new(cert_text)
148
108
  Digest::SHA1.hexdigest(cert.to_der)
data/lib/xml_sec.rb CHANGED
@@ -79,9 +79,6 @@ module XMLSecurity
79
79
  :xmlSecDSigStatusInvalid
80
80
  ]
81
81
 
82
- XMLSEC_ERRORS_R_INVALID_DATA = 12
83
- class XmlSecError < ::RuntimeError; end
84
-
85
82
  class XmlSecPtrList < FFI::Struct
86
83
  layout \
87
84
  :id, :string,
@@ -173,12 +170,6 @@ module XMLSecurity
173
170
  :reserved1, :pointer
174
171
  end
175
172
 
176
- ErrorCallback = FFI::Function.new(:void,
177
- [ :string, :int, :string, :string, :string, :int, :string ]
178
- ) do |file, line, func, errorObject, errorSubject, reason, msg |
179
- XMLSecurity.handle_xmlsec_error_callback(file, line, func, errorObject, errorSubject, reason, msg)
180
- end
181
-
182
173
  # xmlsec functions
183
174
  attach_function :xmlSecInit, [], :int
184
175
  attach_function :xmlSecParseMemory, [ :pointer, :uint, :int ], :pointer
@@ -202,9 +193,7 @@ module XMLSecurity
202
193
  attach_function :xmlSecEncCtxDecrypt, [ :pointer, :pointer ], :int
203
194
  attach_function :xmlSecEncCtxDestroy, [ :pointer ], :void
204
195
 
205
- attach_function :xmlSecErrorsDefaultCallback, [ :string, :int, :string, :string, :string, :int, :string ], :void
206
196
  attach_function :xmlSecErrorsDefaultCallbackEnableOutput, [ :bool ], :void
207
- attach_function :xmlSecErrorsSetCallback, [:pointer], :void
208
197
 
209
198
  attach_function :xmlSecTransformExclC14NGetKlass, [], :pointer
210
199
  attach_function :xmlSecOpenSSLTransformRsaSha1GetKlass, [], :pointer
@@ -249,18 +238,6 @@ module XMLSecurity
249
238
  raise "Failed initializing XMLSec" if self.xmlSecInit < 0
250
239
  raise "Failed initializing app crypto" if self.xmlSecOpenSSLAppInit(nil) < 0
251
240
  raise "Failed initializing crypto" if self.xmlSecOpenSSLInit < 0
252
- self.xmlSecErrorsSetCallback(ErrorCallback)
253
-
254
- def self.handle_xmlsec_error_callback(*args)
255
- raise_exception_if_necessary(*args)
256
- xmlSecErrorsDefaultCallback(*args)
257
- end
258
-
259
- def self.raise_exception_if_necessary(file, line, func, errorObject, errorSubject, reason, msg)
260
- if reason == XMLSEC_ERRORS_R_INVALID_DATA
261
- raise XmlSecError.new(msg)
262
- end
263
- end
264
241
 
265
242
 
266
243
  def self.mute(&block)
@@ -290,29 +267,6 @@ module XMLSecurity
290
267
  "-----BEGIN PUBLIC KEY-----\n#{base64}-----END PUBLIC KEY-----"
291
268
  end
292
269
 
293
- def has_signature?
294
- signatures.any?
295
- end
296
-
297
- def signed_roots
298
- signatures.map do |sig|
299
- ref = sig.find('.//ds:Reference', Onelogin::NAMESPACES).first
300
- signed_element_id = ref['URI'].sub(/^#/, '')
301
-
302
- if signed_element_id.empty?
303
- self.root
304
- else
305
- xpath_id_query = %Q(ancestor::*[@ID = "#{signed_element_id}"])
306
-
307
- ref.find(xpath_id_query, Onelogin::NAMESPACES).first
308
- end
309
- end.compact
310
- end
311
-
312
- def signatures
313
- @signatures ||= self.find("//ds:Signature", Onelogin::NAMESPACES)
314
- end
315
-
316
270
  def validate(idp_cert_fingerprint, logger = nil)
317
271
  # get cert from response
318
272
  base64_cert = self.find_first("//ds:X509Certificate", Onelogin::NAMESPACES).content
@@ -1,9 +1,9 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{ruby-saml-mod}
3
- s.version = "0.1.25"
3
+ s.version = "0.1.26"
4
4
 
5
5
  s.authors = ["OneLogin LLC", "Bracken", "Zach", "Cody", "Jeremy", "Paul"]
6
- s.date = %q{2014-03-12}
6
+ s.date = %q{2013-05-07}
7
7
  s.extra_rdoc_files = [
8
8
  "LICENSE"
9
9
  ]
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-saml-mod
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.25
5
- prerelease:
4
+ version: 0.1.26
6
5
  platform: ruby
7
6
  authors:
8
7
  - OneLogin LLC
@@ -14,12 +13,11 @@ authors:
14
13
  autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
- date: 2014-03-12 00:00:00.000000000 Z
16
+ date: 2013-05-07 00:00:00.000000000 Z
18
17
  dependencies:
19
18
  - !ruby/object:Gem::Dependency
20
19
  name: libxml-ruby
21
20
  requirement: !ruby/object:Gem::Requirement
22
- none: false
23
21
  requirements:
24
22
  - - ! '>='
25
23
  - !ruby/object:Gem::Version
@@ -27,7 +25,6 @@ dependencies:
27
25
  type: :runtime
28
26
  prerelease: false
29
27
  version_requirements: !ruby/object:Gem::Requirement
30
- none: false
31
28
  requirements:
32
29
  - - ! '>='
33
30
  - !ruby/object:Gem::Version
@@ -35,7 +32,6 @@ dependencies:
35
32
  - !ruby/object:Gem::Dependency
36
33
  name: ffi
37
34
  requirement: !ruby/object:Gem::Requirement
38
- none: false
39
35
  requirements:
40
36
  - - ! '>='
41
37
  - !ruby/object:Gem::Version
@@ -43,7 +39,6 @@ dependencies:
43
39
  type: :runtime
44
40
  prerelease: false
45
41
  version_requirements: !ruby/object:Gem::Requirement
46
- none: false
47
42
  requirements:
48
43
  - - ! '>='
49
44
  - !ruby/object:Gem::Version
@@ -72,27 +67,25 @@ files:
72
67
  - ruby-saml-mod.gemspec
73
68
  homepage: http://github.com/bracken/ruby-saml
74
69
  licenses: []
70
+ metadata: {}
75
71
  post_install_message:
76
72
  rdoc_options: []
77
73
  require_paths:
78
74
  - lib
79
75
  required_ruby_version: !ruby/object:Gem::Requirement
80
- none: false
81
76
  requirements:
82
77
  - - ! '>='
83
78
  - !ruby/object:Gem::Version
84
79
  version: '0'
85
80
  required_rubygems_version: !ruby/object:Gem::Requirement
86
- none: false
87
81
  requirements:
88
82
  - - ! '>='
89
83
  - !ruby/object:Gem::Version
90
84
  version: '0'
91
85
  requirements: []
92
86
  rubyforge_project:
93
- rubygems_version: 1.8.23
87
+ rubygems_version: 2.0.3
94
88
  signing_key:
95
- specification_version: 3
89
+ specification_version: 4
96
90
  summary: Ruby library for SAML service providers
97
91
  test_files: []
98
- has_rdoc: