ruby-saml-mod 0.1.19 → 0.1.20
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.
- data/lib/onelogin/saml.rb +1 -0
- data/lib/onelogin/saml/log_out_request.rb +27 -5
- data/lib/onelogin/saml/meta_data.rb +14 -0
- data/lib/onelogin/saml/settings.rb +4 -0
- data/lib/xml_sec.rb +96 -0
- data/ruby-saml-mod.gemspec +3 -6
- metadata +46 -90
data/lib/onelogin/saml.rb
CHANGED
@@ -16,19 +16,41 @@ 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}\"
|
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
20
|
"<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{@settings.issuer}</saml:Issuer>" +
|
21
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
22
|
"<samlp:SessionIndex xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">#{@session[:session_index]}</samlp:SessionIndex>" +
|
23
23
|
"</samlp:LogoutRequest>"
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
if settings.sign?
|
26
|
+
@request_xml = XMLSecurity.sign(@request_xml, @settings.xmlsec_privatekey)
|
27
|
+
end
|
28
28
|
|
29
|
-
|
29
|
+
deflated_logout_request = Zlib::Deflate.deflate(@request_xml, 9)[2..-5]
|
30
|
+
base64_logout_request = Base64.encode64(deflated_logout_request)
|
31
|
+
|
32
|
+
url, existing_query_string = @settings.idp_slo_target_url.split('?')
|
33
|
+
query_string = _query_string_append(existing_query_string, 'SAMLRequest', base64_logout_request)
|
34
|
+
|
35
|
+
if settings.sign?
|
36
|
+
query_string = _query_string_append(query_string, "SigAlg", "http://www.w3.org/2000/09/xmldsig#rsa-sha1")
|
37
|
+
signature = _generate_signature(query_string, @settings.xmlsec_privatekey)
|
38
|
+
query_string = _query_string_append(query_string, "Signature", signature)
|
39
|
+
end
|
40
|
+
|
41
|
+
@forward_url = [url, query_string].join("?")
|
30
42
|
|
31
43
|
@forward_url
|
32
44
|
end
|
45
|
+
|
46
|
+
def _generate_signature(string, private_key)
|
47
|
+
pkey = OpenSSL::PKey::RSA.new(File.read(private_key))
|
48
|
+
sign = pkey.sign(OpenSSL::Digest::SHA1.new, string)
|
49
|
+
Base64.encode64(sign).gsub(/\s/, '')
|
50
|
+
end
|
51
|
+
|
52
|
+
def _query_string_append(query_string, key, value)
|
53
|
+
[query_string, "#{CGI.escape(key)}=#{CGI.escape(value)}"].compact.join('&')
|
54
|
+
end
|
33
55
|
end
|
34
56
|
end
|
@@ -21,6 +21,20 @@ module Onelogin::Saml
|
|
21
21
|
</KeyDescriptor>
|
22
22
|
}
|
23
23
|
end
|
24
|
+
if settings.sign?
|
25
|
+
xml += %{
|
26
|
+
<KeyDescriptor use="signing">
|
27
|
+
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
|
28
|
+
<X509Data>
|
29
|
+
<X509Certificate>
|
30
|
+
#{File.read(settings.xmlsec_certificate).gsub(/\w*-+(BEGIN|END) CERTIFICATE-+\w*/, "").strip}
|
31
|
+
</X509Certificate>
|
32
|
+
</X509Data>
|
33
|
+
</KeyInfo>
|
34
|
+
</KeyDescriptor>
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
24
38
|
xml += %{
|
25
39
|
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="#{settings.sp_slo_url}"/>
|
26
40
|
}
|
data/lib/xml_sec.rb
CHANGED
@@ -192,17 +192,58 @@ module XMLSecurity
|
|
192
192
|
attach_function :xmlSecEncCtxDecrypt, [ :pointer, :pointer ], :int
|
193
193
|
attach_function :xmlSecEncCtxDestroy, [ :pointer ], :void
|
194
194
|
|
195
|
+
attach_function :xmlSecErrorsDefaultCallbackEnableOutput, [ :bool ], :void
|
196
|
+
|
197
|
+
attach_function :xmlSecTransformExclC14NGetKlass, [], :pointer
|
198
|
+
attach_function :xmlSecOpenSSLTransformRsaSha1GetKlass, [], :pointer
|
199
|
+
attach_function :xmlSecOpenSSLTransformSha1GetKlass, [], :pointer
|
200
|
+
|
201
|
+
attach_function :xmlSecTmplSignatureCreate, [ :pointer, :pointer, :pointer, :string ], :pointer
|
202
|
+
attach_function :xmlSecTmplSignatureAddReference, [ :pointer, :pointer, :pointer, :pointer, :pointer ], :pointer
|
203
|
+
attach_function :xmlSecTransformEnvelopedGetKlass, [], :pointer
|
204
|
+
attach_function :xmlSecTmplSignatureEnsureKeyInfo, [ :pointer, :pointer ], :pointer
|
205
|
+
attach_function :xmlSecTmplReferenceAddTransform, [ :pointer, :pointer ], :pointer
|
206
|
+
|
207
|
+
attach_function :xmlSecKeySetName, [ :pointer, :string ], :int
|
208
|
+
|
209
|
+
attach_function :xmlSecTmplKeyInfoAddKeyName, [ :pointer, :pointer ], :pointer
|
210
|
+
|
211
|
+
attach_function :xmlSecDSigCtxSign, [ :pointer, :pointer ], :int
|
212
|
+
|
213
|
+
|
214
|
+
|
215
|
+
|
195
216
|
# libxml functions
|
196
217
|
attach_function :xmlInitParser, [], :void
|
197
218
|
attach_function :xmlDocGetRootElement, [ :pointer ], :pointer
|
198
219
|
attach_function :xmlDocDumpFormatMemory, [ :pointer, :pointer, :pointer, :int ], :void
|
199
220
|
attach_function :xmlFreeDoc, [ :pointer ], :void
|
221
|
+
attach_function :xmlParseMemory, [ :pointer, :int ], :pointer
|
222
|
+
attach_function :xmlAddChild, [ :pointer, :pointer ], :pointer
|
223
|
+
|
224
|
+
attach_variable :__xmlFree, :xmlFree, callback([ :pointer ], :void)
|
225
|
+
attach_variable :__xmlMalloc, :xmlMalloc, callback([ :size_t ], :pointer)
|
226
|
+
|
227
|
+
def self.xmlMalloc(size)
|
228
|
+
__xmlMalloc.call(size)
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.xmlFree(ptr)
|
232
|
+
__xmlFree.call(ptr)
|
233
|
+
end
|
200
234
|
|
201
235
|
self.xmlInitParser
|
202
236
|
raise "Failed initializing XMLSec" if self.xmlSecInit < 0
|
203
237
|
raise "Failed initializing app crypto" if self.xmlSecOpenSSLAppInit(nil) < 0
|
204
238
|
raise "Failed initializing crypto" if self.xmlSecOpenSSLInit < 0
|
205
239
|
|
240
|
+
|
241
|
+
def self.mute(&block)
|
242
|
+
xmlSecErrorsDefaultCallbackEnableOutput(false)
|
243
|
+
block.call
|
244
|
+
xmlSecErrorsDefaultCallbackEnableOutput(true)
|
245
|
+
end
|
246
|
+
|
206
247
|
module SignedDocument
|
207
248
|
attr_reader :validation_error
|
208
249
|
|
@@ -350,4 +391,59 @@ module XMLSecurity
|
|
350
391
|
result
|
351
392
|
end
|
352
393
|
end
|
394
|
+
|
395
|
+
class SignatureFailure < RuntimeError; end
|
396
|
+
|
397
|
+
def self.sign(xml_string, private_key)
|
398
|
+
doc = self.xmlParseMemory(xml_string, xml_string.size)
|
399
|
+
raise SignatureFailure.new("could not parse XML document") if doc.null?
|
400
|
+
|
401
|
+
canonicalization_method_id = self.xmlSecTransformExclC14NGetKlass
|
402
|
+
sign_method_id = self.xmlSecOpenSSLTransformRsaSha1GetKlass
|
403
|
+
|
404
|
+
sign_node = self.xmlSecTmplSignatureCreate(doc, canonicalization_method_id, sign_method_id, nil)
|
405
|
+
|
406
|
+
raise SignatureFailure.new("failed to create signature template") if sign_node.null?
|
407
|
+
self.xmlAddChild(self.xmlDocGetRootElement(doc), sign_node)
|
408
|
+
|
409
|
+
ref_node = self.xmlSecTmplSignatureAddReference(sign_node, self.xmlSecOpenSSLTransformSha1GetKlass, nil, nil, nil)
|
410
|
+
raise SignatureFailure.new("failed to add a reference") if ref_node.null?
|
411
|
+
|
412
|
+
envelope_result = self.xmlSecTmplReferenceAddTransform(ref_node, self.xmlSecTransformEnvelopedGetKlass)
|
413
|
+
raise SignatureFailure.new("failed to add envelope transform to reference") if envelope_result.null?
|
414
|
+
|
415
|
+
key_info_node = self.xmlSecTmplSignatureEnsureKeyInfo(sign_node, nil)
|
416
|
+
raise SignatureFailure.new("failed to add key info") if key_info_node.null?
|
417
|
+
|
418
|
+
digital_signature_context = self.xmlSecDSigCtxCreate(nil)
|
419
|
+
raise SignatureFailure.new("failed to create signature context") if digital_signature_context.null?
|
420
|
+
|
421
|
+
digital_signature_context[:signKey] = self.xmlSecOpenSSLAppKeyLoad(private_key, :xmlSecKeyDataFormatPem, nil, nil, nil)
|
422
|
+
raise SignatureFailure.new("failed to load private pem ley from #{private_key}") if digital_signature_context[:signKey].null?
|
423
|
+
|
424
|
+
if self.xmlSecKeySetName(digital_signature_context[:signKey], File.basename(private_key)) < 0
|
425
|
+
raise SignatureFailure.new("failed to set key name for key of #{private_key}")
|
426
|
+
end
|
427
|
+
|
428
|
+
if self.xmlSecTmplKeyInfoAddKeyName(key_info_node, nil).null?
|
429
|
+
raise SignatureFailure.new("failed to add key info")
|
430
|
+
end
|
431
|
+
|
432
|
+
if self.xmlSecDSigCtxSign(digital_signature_context, sign_node) < 0
|
433
|
+
raise SignatureFailure.new("signature failed!")
|
434
|
+
end
|
435
|
+
|
436
|
+
ptr = FFI::MemoryPointer.new(:pointer, 1)
|
437
|
+
sizeptr = FFI::MemoryPointer.new(:pointer, 1)
|
438
|
+
self.xmlDocDumpFormatMemory(doc, ptr, sizeptr, 1)
|
439
|
+
strptr = ptr.read_pointer
|
440
|
+
result = strptr.null? ? nil : strptr.read_string
|
441
|
+
ensure
|
442
|
+
ptr.free if defined?(ptr) && ptr
|
443
|
+
sizeptr.free if defined?(sizeptr) && sizeptr
|
444
|
+
self.xmlFreeDoc(doc) if defined?(doc) && doc && !doc.null?
|
445
|
+
self.xmlSecDSigCtxDestroy(digital_signature_context) if defined?(digital_signature_context) && digital_signature_context && !digital_signature_context.null?
|
446
|
+
self.xmlFree(strptr) if defined?(strptr) && strptr && !strptr.null?
|
447
|
+
end
|
448
|
+
|
353
449
|
end
|
data/ruby-saml-mod.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{ruby-saml-mod}
|
3
|
-
s.version = "0.1.
|
3
|
+
s.version = "0.1.20"
|
4
4
|
|
5
|
-
s.authors = ["OneLogin LLC", "Bracken", "Zach", "Cody", "Jeremy"]
|
6
|
-
s.date = %q{
|
5
|
+
s.authors = ["OneLogin LLC", "Bracken", "Zach", "Cody", "Jeremy", "Paul"]
|
6
|
+
s.date = %q{2013-02-15}
|
7
7
|
s.extra_rdoc_files = [
|
8
8
|
"LICENSE"
|
9
9
|
]
|
@@ -26,9 +26,6 @@ Gem::Specification.new do |s|
|
|
26
26
|
s.add_dependency('libxml-ruby', '>= 2.3.0')
|
27
27
|
s.add_dependency('ffi')
|
28
28
|
|
29
|
-
s.add_development_dependency 'ruby-debug'
|
30
|
-
s.add_development_dependency 'rspec', '1.3.2'
|
31
|
-
|
32
29
|
s.homepage = %q{http://github.com/bracken/ruby-saml}
|
33
30
|
s.require_paths = ["lib"]
|
34
31
|
s.summary = %q{Ruby library for SAML service providers}
|
metadata
CHANGED
@@ -1,95 +1,61 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-saml-mod
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.20
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 19
|
10
|
-
version: 0.1.19
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- OneLogin LLC
|
14
9
|
- Bracken
|
15
10
|
- Zach
|
16
11
|
- Cody
|
17
12
|
- Jeremy
|
13
|
+
- Paul
|
18
14
|
autorequire:
|
19
15
|
bindir: bin
|
20
16
|
cert_chain: []
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
- !ruby/object:Gem::Dependency
|
17
|
+
date: 2013-02-15 00:00:00.000000000 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
25
20
|
name: libxml-ruby
|
26
|
-
|
27
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
21
|
+
requirement: !ruby/object:Gem::Requirement
|
28
22
|
none: false
|
29
|
-
requirements:
|
30
|
-
- -
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
hash: 3
|
33
|
-
segments:
|
34
|
-
- 2
|
35
|
-
- 3
|
36
|
-
- 0
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
37
26
|
version: 2.3.0
|
38
27
|
type: :runtime
|
39
|
-
version_requirements: *id001
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: ffi
|
42
28
|
prerelease: false
|
43
|
-
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
30
|
none: false
|
45
|
-
requirements:
|
46
|
-
- -
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
type: :runtime
|
53
|
-
version_requirements: *id002
|
54
|
-
- !ruby/object:Gem::Dependency
|
55
|
-
name: ruby-debug
|
56
|
-
prerelease: false
|
57
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ! '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 2.3.0
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: ffi
|
37
|
+
requirement: !ruby/object:Gem::Requirement
|
58
38
|
none: false
|
59
|
-
requirements:
|
60
|
-
- -
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
|
64
|
-
- 0
|
65
|
-
version: "0"
|
66
|
-
type: :development
|
67
|
-
version_requirements: *id003
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
|
-
name: rspec
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
type: :runtime
|
70
44
|
prerelease: false
|
71
|
-
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
46
|
none: false
|
73
|
-
requirements:
|
74
|
-
- -
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
- 3
|
80
|
-
- 2
|
81
|
-
version: 1.3.2
|
82
|
-
type: :development
|
83
|
-
version_requirements: *id004
|
84
|
-
description: "This is an early fork from https://github.com/onelogin/ruby-saml - I plan to \"rebase\" these changes ontop of their current version eventually. "
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
description: ! 'This is an early fork from https://github.com/onelogin/ruby-saml -
|
52
|
+
I plan to "rebase" these changes ontop of their current version eventually. '
|
85
53
|
email:
|
86
54
|
executables: []
|
87
|
-
|
88
55
|
extensions: []
|
89
|
-
|
90
|
-
extra_rdoc_files:
|
56
|
+
extra_rdoc_files:
|
91
57
|
- LICENSE
|
92
|
-
files:
|
58
|
+
files:
|
93
59
|
- LICENSE
|
94
60
|
- README
|
95
61
|
- lib/onelogin/saml.rb
|
@@ -106,37 +72,27 @@ files:
|
|
106
72
|
- ruby-saml-mod.gemspec
|
107
73
|
homepage: http://github.com/bracken/ruby-saml
|
108
74
|
licenses: []
|
109
|
-
|
110
75
|
post_install_message:
|
111
76
|
rdoc_options: []
|
112
|
-
|
113
|
-
require_paths:
|
77
|
+
require_paths:
|
114
78
|
- lib
|
115
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
80
|
none: false
|
117
|
-
requirements:
|
118
|
-
- -
|
119
|
-
- !ruby/object:Gem::Version
|
120
|
-
|
121
|
-
|
122
|
-
- 0
|
123
|
-
version: "0"
|
124
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
86
|
none: false
|
126
|
-
requirements:
|
127
|
-
- -
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
|
130
|
-
segments:
|
131
|
-
- 0
|
132
|
-
version: "0"
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
133
91
|
requirements: []
|
134
|
-
|
135
92
|
rubyforge_project:
|
136
|
-
rubygems_version: 1.8.
|
93
|
+
rubygems_version: 1.8.24
|
137
94
|
signing_key:
|
138
95
|
specification_version: 3
|
139
96
|
summary: Ruby library for SAML service providers
|
140
97
|
test_files: []
|
141
|
-
|
142
98
|
has_rdoc:
|