ruby-saml-mod 0.1.19 → 0.1.20
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|