ruby-saml-mod 0.1.21 → 0.1.22

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,14 +16,16 @@ module Onelogin::Saml
16
16
  @id = Onelogin::Saml::AuthRequest.generate_unique_id(42)
17
17
  issue_instant = Onelogin::Saml::AuthRequest.get_timestamp
18
18
 
19
- @request_xml = "<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}\">" +
20
- "<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{@settings.issuer}</saml:Issuer>" +
21
- "<saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" NameQualifier=\"#{@session[:name_qualifier]}\" SPNameQualifier=\"#{@settings.issuer}\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:transient\">#{@session[:name_id]}</saml:NameID>" +
22
- "<samlp:SessionIndex xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">#{@session[:session_index]}</samlp:SessionIndex>" +
23
- "</samlp:LogoutRequest>"
19
+ @request_xml = <<-REQUEST_XML
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
+ <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">#{@settings.issuer}</saml:Issuer>
22
+ <saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" NameQualifier="#{@session[:name_qualifier]}" SPNameQualifier="#{@settings.issuer}" Format="#{@settings.name_identifier_format}">#{@session[:name_id]}</saml:NameID>
23
+ <samlp:SessionIndex xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">#{@session[:session_index]}</samlp:SessionIndex>
24
+ </samlp:LogoutRequest>
25
+ REQUEST_XML
24
26
 
25
27
  if settings.sign?
26
- @request_xml = XMLSecurity.sign(@request_xml, @settings.xmlsec_privatekey)
28
+ @request_xml = XMLSecurity.sign(@id, @request_xml, @settings.xmlsec_privatekey, @settings.xmlsec_certificate)
27
29
  end
28
30
 
29
31
  deflated_logout_request = Zlib::Deflate.deflate(@request_xml, 9)[2..-5]
data/lib/xml_sec.rb CHANGED
@@ -184,6 +184,7 @@ module XMLSecurity
184
184
  attach_function :xmlSecKeysMngrCreate, [], :pointer
185
185
  attach_function :xmlSecOpenSSLAppDefaultKeysMngrInit, [ :pointer ], :int
186
186
  attach_function :xmlSecOpenSSLAppKeyLoad, [ :string, :xmlSecKeyDataFormat, :pointer, :pointer, :pointer ], :pointer
187
+ attach_function :xmlSecOpenSSLAppKeyCertLoad, [ :pointer, :string, :xmlSecKeyDataFormat], :int
187
188
  attach_function :xmlSecOpenSSLAppKeyLoadMemory, [ :pointer, :uint, :xmlSecKeyDataFormat, :pointer, :pointer, :pointer ], :pointer
188
189
  attach_function :xmlSecOpenSSLAppDefaultKeysMngrAdoptKey, [ :pointer, :pointer ], :int
189
190
  attach_function :xmlSecKeysMngrDestroy, [ :pointer ], :void
@@ -207,6 +208,7 @@ module XMLSecurity
207
208
  attach_function :xmlSecKeySetName, [ :pointer, :string ], :int
208
209
 
209
210
  attach_function :xmlSecTmplKeyInfoAddKeyName, [ :pointer, :pointer ], :pointer
211
+ attach_function :xmlSecTmplKeyInfoAddX509Data, [ :pointer ], :pointer
210
212
 
211
213
  attach_function :xmlSecDSigCtxSign, [ :pointer, :pointer ], :int
212
214
 
@@ -308,11 +310,7 @@ module XMLSecurity
308
310
  doc = XMLSecurity.xmlSecParseMemory(xml, xml.length, 0)
309
311
  root = XMLSecurity.xmlDocGetRootElement(doc)
310
312
 
311
- # add the ID attribute as an id. yeah, hacky
312
- idary = FFI::MemoryPointer.new(:pointer, 2)
313
- idary[0].put_pointer(0, FFI::MemoryPointer.from_string("ID"))
314
- idary[1].put_pointer(0, nil)
315
- XMLSecurity.xmlSecAddIDs(doc, root, idary)
313
+ XMLSecurity.register_xml_id_attribute(doc, root)
316
314
 
317
315
  # get the root node, and then find the signature
318
316
  node = XMLSecurity.xmlSecFindNode(root, "Signature", "http://www.w3.org/2000/09/xmldsig#")
@@ -402,7 +400,7 @@ module XMLSecurity
402
400
 
403
401
  class SignatureFailure < RuntimeError; end
404
402
 
405
- def self.sign(xml_string, private_key)
403
+ def self.sign(reference_id, xml_string, private_key, certificate)
406
404
  doc = self.xmlParseMemory(xml_string, xml_string.size)
407
405
  raise SignatureFailure.new("could not parse XML document") if doc.null?
408
406
 
@@ -412,9 +410,12 @@ module XMLSecurity
412
410
  sign_node = self.xmlSecTmplSignatureCreate(doc, canonicalization_method_id, sign_method_id, nil)
413
411
 
414
412
  raise SignatureFailure.new("failed to create signature template") if sign_node.null?
415
- self.xmlAddChild(self.xmlDocGetRootElement(doc), sign_node)
413
+ root = self.xmlDocGetRootElement(doc)
414
+ self.xmlAddChild(root, sign_node)
416
415
 
417
- ref_node = self.xmlSecTmplSignatureAddReference(sign_node, self.xmlSecOpenSSLTransformSha1GetKlass, nil, nil, nil)
416
+ XMLSecurity.register_xml_id_attribute(doc, root)
417
+
418
+ ref_node = self.xmlSecTmplSignatureAddReference(sign_node, self.xmlSecOpenSSLTransformSha1GetKlass, nil, reference_id && "##{reference_id}", nil)
418
419
  raise SignatureFailure.new("failed to add a reference") if ref_node.null?
419
420
 
420
421
  envelope_result = self.xmlSecTmplReferenceAddTransform(ref_node, self.xmlSecTransformEnvelopedGetKlass)
@@ -427,15 +428,14 @@ module XMLSecurity
427
428
  raise SignatureFailure.new("failed to create signature context") if digital_signature_context.null?
428
429
 
429
430
  digital_signature_context[:signKey] = self.xmlSecOpenSSLAppKeyLoad(private_key, :xmlSecKeyDataFormatPem, nil, nil, nil)
430
- raise SignatureFailure.new("failed to load private pem ley from #{private_key}") if digital_signature_context[:signKey].null?
431
+ raise SignatureFailure.new("failed to load private pem key from #{private_key}") if digital_signature_context[:signKey].null?
431
432
 
432
- if self.xmlSecKeySetName(digital_signature_context[:signKey], File.basename(private_key)) < 0
433
- raise SignatureFailure.new("failed to set key name for key of #{private_key}")
433
+ if self.xmlSecOpenSSLAppKeyCertLoad(digital_signature_context[:signKey], certificate, :xmlSecKeyDataFormatPem) < 0
434
+ raise SignatureFailure.new("failed to load public cert from #{certificate}")
434
435
  end
435
436
 
436
- if self.xmlSecTmplKeyInfoAddKeyName(key_info_node, nil).null?
437
- raise SignatureFailure.new("failed to add key info")
438
- end
437
+ x509_data_node = self.xmlSecTmplKeyInfoAddX509Data(key_info_node)
438
+ raise SignatureFailure.new("failed to add <dsig:X509Data/> node") if x509_data_node.null?
439
439
 
440
440
  if self.xmlSecDSigCtxSign(digital_signature_context, sign_node) < 0
441
441
  raise SignatureFailure.new("signature failed!")
@@ -443,9 +443,10 @@ module XMLSecurity
443
443
 
444
444
  ptr = FFI::MemoryPointer.new(:pointer, 1)
445
445
  sizeptr = FFI::MemoryPointer.new(:pointer, 1)
446
- self.xmlDocDumpFormatMemory(doc, ptr, sizeptr, 1)
446
+ self.xmlDocDumpFormatMemory(doc, ptr, sizeptr, 0)
447
447
  strptr = ptr.read_pointer
448
- result = strptr.null? ? nil : strptr.read_string
448
+
449
+ return strptr.null? ? nil : strptr.read_string
449
450
  ensure
450
451
  ptr.free if defined?(ptr) && ptr
451
452
  sizeptr.free if defined?(sizeptr) && sizeptr
@@ -454,4 +455,25 @@ module XMLSecurity
454
455
  self.xmlFree(strptr) if defined?(strptr) && strptr && !strptr.null?
455
456
  end
456
457
 
458
+
459
+ #
460
+ # Register 'ID' as an XML id attribute so we can properly sign/validate
461
+ # signatures with references of the form:
462
+ #
463
+ # <dsig:Reference URI="#IdOfElementImSigning" />
464
+ #
465
+ # Which refer to another element in the same document like:
466
+ #
467
+ # <elem ID="IdOfElementImSigning" />
468
+ #
469
+ # For more information see:
470
+ #
471
+ # http://www.aleksey.com/xmlsec/faq.html#section_3_4
472
+ #
473
+ def self.register_xml_id_attribute(doc, root)
474
+ idary = FFI::MemoryPointer.new(:pointer, 2)
475
+ idary[0].put_pointer(0, FFI::MemoryPointer.from_string("ID"))
476
+ idary[1].put_pointer(0, nil)
477
+ XMLSecurity.xmlSecAddIDs(doc, root, idary)
478
+ end
457
479
  end
@@ -1,9 +1,9 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{ruby-saml-mod}
3
- s.version = "0.1.21"
3
+ s.version = "0.1.22"
4
4
 
5
5
  s.authors = ["OneLogin LLC", "Bracken", "Zach", "Cody", "Jeremy", "Paul"]
6
- s.date = %q{2013-03-07}
6
+ s.date = %q{2013-05-07}
7
7
  s.extra_rdoc_files = [
8
8
  "LICENSE"
9
9
  ]
metadata CHANGED
@@ -1,7 +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.21
4
+ version: 0.1.22
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2013-03-07 00:00:00.000000000 Z
17
+ date: 2013-05-07 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: libxml-ruby
@@ -95,3 +95,4 @@ signing_key:
95
95
  specification_version: 3
96
96
  summary: Ruby library for SAML service providers
97
97
  test_files: []
98
+ has_rdoc: