ruby-saml-mod 0.2.5 → 0.2.6
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 +4 -4
- data/lib/onelogin/saml.rb +1 -1
- data/lib/onelogin/saml/base_assertion.rb +3 -3
- data/lib/onelogin/saml/response.rb +11 -10
- data/lib/xml_sec.rb +9 -23
- data/spec/logout_request_spec.rb +6 -6
- data/spec/logout_response_spec.rb +7 -7
- data/spec/meta_data_spec.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9717bd6a9dffb64cf2ae4f45ff7f386059af316
|
4
|
+
data.tar.gz: 363c5cedd4ec2a9705129c559547e5fd0336ebf9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 466ef19f37dcddd3f17fa608e1fe6981cec73228463adc876fd610ff7b637a9c7cbb9301910e0c44e9153c20dc126baed7ab0007f72ee287bdcb57090864cbdd
|
7
|
+
data.tar.gz: fa770d00d673b9c5a5fd42a1492b9260049554c3c146c941f86ed881a63f5bca351f8786560ad06bf31e5f9478914a208905ec531f5e2b8f9311f78adc608e97
|
data/lib/onelogin/saml.rb
CHANGED
@@ -29,7 +29,7 @@ module Onelogin::Saml
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def document
|
32
|
-
@document ||=
|
32
|
+
@document ||= Nokogiri::XML(xml) if xml
|
33
33
|
end
|
34
34
|
|
35
35
|
def xml=(value)
|
@@ -117,11 +117,11 @@ module Onelogin::Saml
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def node_attribute_value(xpath, attribute)
|
120
|
-
document.root.
|
120
|
+
document.root.at_xpath(xpath, Onelogin::NAMESPACES)[attribute] rescue nil
|
121
121
|
end
|
122
122
|
|
123
123
|
def node_content(xpath)
|
124
|
-
document.root.
|
124
|
+
document.root.at_xpath(xpath, Onelogin::NAMESPACES).content rescue nil
|
125
125
|
end
|
126
126
|
|
127
127
|
def self.generate_unique_id(length = 42)
|
@@ -13,7 +13,7 @@ module Onelogin::Saml
|
|
13
13
|
|
14
14
|
begin
|
15
15
|
@xml = Base64.decode64(@response)
|
16
|
-
@document =
|
16
|
+
@document = Nokogiri::XML(@xml)
|
17
17
|
@document.extend(XMLSecurity::SignedDocument)
|
18
18
|
rescue
|
19
19
|
# could not parse document, everything is invalid
|
@@ -21,9 +21,9 @@ module Onelogin::Saml
|
|
21
21
|
return
|
22
22
|
end
|
23
23
|
|
24
|
-
@issuer = document.
|
25
|
-
@issuer ||= document.
|
26
|
-
@status_code = document.
|
24
|
+
@issuer = document.at_xpath("/samlp:Response/saml:Issuer", Onelogin::NAMESPACES).content.strip rescue nil
|
25
|
+
@issuer ||= document.at_xpath("/samlp:Response/saml:Assertion/saml:Issuer", Onelogin::NAMESPACES).content.strip rescue nil
|
26
|
+
@status_code = document.at_xpath("/samlp:Response/samlp:Status/samlp:StatusCode", Onelogin::NAMESPACES)["Value"] rescue nil
|
27
27
|
|
28
28
|
process(settings) if settings
|
29
29
|
end
|
@@ -55,14 +55,15 @@ module Onelogin::Saml
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def decrypted_document
|
58
|
-
@decrypted_document
|
59
|
-
|
60
|
-
|
58
|
+
unless @decrypted_document
|
59
|
+
document.decrypt!(settings)
|
60
|
+
@decrypted_document = document
|
61
61
|
end
|
62
|
+
@decrypted_document
|
62
63
|
end
|
63
64
|
|
64
65
|
def untrusted_find_first(xpath)
|
65
|
-
decrypted_document.
|
66
|
+
decrypted_document.at_xpath(xpath, Onelogin::NAMESPACES)
|
66
67
|
end
|
67
68
|
|
68
69
|
def trusted_find_first(xpath)
|
@@ -71,7 +72,7 @@ module Onelogin::Saml
|
|
71
72
|
|
72
73
|
def trusted_find(xpath)
|
73
74
|
trusted_roots.map do |trusted_root|
|
74
|
-
trusted_root.
|
75
|
+
trusted_root.xpath("descendant-or-self::#{xpath}", Onelogin::NAMESPACES).to_a
|
75
76
|
end.flatten.compact
|
76
77
|
end
|
77
78
|
|
@@ -141,7 +142,7 @@ module Onelogin::Saml
|
|
141
142
|
end
|
142
143
|
|
143
144
|
def fingerprint_from_idp
|
144
|
-
if base64_cert = decrypted_document.
|
145
|
+
if base64_cert = decrypted_document.at_xpath("//ds:X509Certificate", Onelogin::NAMESPACES)
|
145
146
|
cert_text = Base64.decode64(base64_cert.content)
|
146
147
|
cert = OpenSSL::X509::Certificate.new(cert_text)
|
147
148
|
Digest::SHA1.hexdigest(cert.to_der)
|
data/lib/xml_sec.rb
CHANGED
@@ -25,7 +25,7 @@
|
|
25
25
|
require 'rubygems'
|
26
26
|
require 'ffi'
|
27
27
|
require 'base64'
|
28
|
-
require "
|
28
|
+
require "nokogiri"
|
29
29
|
require "openssl"
|
30
30
|
require "digest/sha1"
|
31
31
|
|
@@ -330,7 +330,7 @@ module XMLSecurity
|
|
330
330
|
|
331
331
|
def signed_roots
|
332
332
|
signatures.map do |sig|
|
333
|
-
ref = sig.
|
333
|
+
ref = sig.at_xpath('./ds:SignedInfo/ds:Reference', Onelogin::NAMESPACES)
|
334
334
|
signed_element_id = ref['URI'].sub(/^#/, '')
|
335
335
|
|
336
336
|
if signed_element_id.empty?
|
@@ -338,19 +338,19 @@ module XMLSecurity
|
|
338
338
|
else
|
339
339
|
xpath_id_query = %Q(ancestor::*[@ID = "#{signed_element_id}"])
|
340
340
|
|
341
|
-
ref.
|
341
|
+
ref.at_xpath(xpath_id_query, Onelogin::NAMESPACES)
|
342
342
|
end
|
343
343
|
end.compact
|
344
344
|
end
|
345
345
|
|
346
346
|
def signatures
|
347
347
|
# we only return the first, cause our signature validation only checks the first
|
348
|
-
@signatures ||= [self.
|
348
|
+
@signatures ||= [self.at_xpath("//ds:Signature", Onelogin::NAMESPACES)].compact
|
349
349
|
end
|
350
350
|
|
351
351
|
def validate(idp_cert_fingerprint, logger = nil)
|
352
352
|
# get cert from response
|
353
|
-
base64_cert = self.
|
353
|
+
base64_cert = self.at_xpath("//ds:X509Certificate", Onelogin::NAMESPACES).content
|
354
354
|
cert_text = Base64.decode64(base64_cert)
|
355
355
|
cert = OpenSSL::X509::Certificate.new(cert_text)
|
356
356
|
|
@@ -364,21 +364,8 @@ module XMLSecurity
|
|
364
364
|
end
|
365
365
|
end
|
366
366
|
|
367
|
-
# create a copy of the document with the certificate removed
|
368
|
-
doc = LibXML::XML::Document.new
|
369
|
-
# doc.encoding = self.encoding == XML::Encoding::NONE ? XML::Encoding::ISO_8859_1 : self.encoding
|
370
|
-
|
371
|
-
# for some reason xmlsec doesn't like it when its UTF-8 and has other
|
372
|
-
# characters with umlauts and the like. We will just force it to another encoding.
|
373
|
-
# This should work fine since we are just validating the signature.
|
374
|
-
doc.encoding = XML::Encoding::ISO_8859_1
|
375
|
-
|
376
|
-
doc.root = doc.import(self.root)
|
377
|
-
sigcert = doc.find_first("//ds:Signature/ds:KeyInfo", Onelogin::NAMESPACES)
|
378
|
-
sigcert.remove!
|
379
|
-
|
380
367
|
# Force encoding of the xml and the xml string for validation
|
381
|
-
xml =
|
368
|
+
xml = to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML, encoding: "ISO-8859-1")
|
382
369
|
|
383
370
|
# validate it!
|
384
371
|
validate_doc(xml, SignedDocument.format_cert(cert))
|
@@ -432,14 +419,13 @@ module XMLSecurity
|
|
432
419
|
# replaces EncryptedData nodes with decrypted copies
|
433
420
|
def decrypt!(settings)
|
434
421
|
if settings.encryption_configured?
|
435
|
-
|
422
|
+
xpath("//xenc:EncryptedData", Onelogin::NAMESPACES).each do |node|
|
436
423
|
decrypted_xml = decrypt_node(settings, node.to_s)
|
437
424
|
if decrypted_xml
|
438
|
-
decrypted_doc =
|
425
|
+
decrypted_doc = Nokogiri::XML(decrypted_xml)
|
439
426
|
decrypted_node = decrypted_doc.root
|
440
|
-
decrypted_node = self.import(decrypted_node)
|
441
427
|
node.parent.next = decrypted_node
|
442
|
-
node.parent.
|
428
|
+
node.parent.unlink
|
443
429
|
end
|
444
430
|
end
|
445
431
|
end
|
data/spec/logout_request_spec.rb
CHANGED
@@ -43,18 +43,18 @@ describe Onelogin::Saml::LogoutRequest do
|
|
43
43
|
let(:forward_url) { logout_request.forward_url }
|
44
44
|
|
45
45
|
it "includes destination in the saml:LogoutRequest attributes" do
|
46
|
-
logout_xml =
|
47
|
-
logout_xml.
|
46
|
+
logout_xml = Nokogiri::XML(logout_request.xml)
|
47
|
+
logout_xml.at_xpath('/samlp:LogoutRequest', Onelogin::NAMESPACES)['Destination'].should == "http://idp.example.com/saml2"
|
48
48
|
end
|
49
49
|
|
50
50
|
it "properly sets the Format attribute NameID based on settings" do
|
51
|
-
logout_xml =
|
52
|
-
logout_xml.
|
51
|
+
logout_xml = Nokogiri::XML(logout_request.xml)
|
52
|
+
logout_xml.at_xpath('/samlp:LogoutRequest/saml:NameID', Onelogin::NAMESPACES)['Format'].should == Onelogin::Saml::NameIdentifiers::UNSPECIFIED
|
53
53
|
end
|
54
54
|
|
55
55
|
it "does not include the signature in the request xml" do
|
56
|
-
logout_xml =
|
57
|
-
logout_xml.
|
56
|
+
logout_xml = Nokogiri::XML(logout_request.xml)
|
57
|
+
logout_xml.at_xpath('/samlp:LogoutRequest/ds:Signature', Onelogin::NAMESPACES).should be_nil
|
58
58
|
end
|
59
59
|
|
60
60
|
it "can sign the generated query string" do
|
@@ -25,37 +25,37 @@ describe Onelogin::Saml::LogoutResponse do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it "includes destination in the saml:LogoutRequest attributes" do
|
28
|
-
value = xml.
|
28
|
+
value = xml.at_xpath('/samlp:LogoutResponse', Onelogin::NAMESPACES)['Destination']
|
29
29
|
expect(value).to eq "http://idp.example.com/saml2?existing=param&existing=param"
|
30
30
|
end
|
31
31
|
|
32
32
|
it "includes id in the saml:LogoutRequest attributes" do
|
33
|
-
value = xml.
|
33
|
+
value = xml.at_xpath('/samlp:LogoutResponse', Onelogin::NAMESPACES)['ID']
|
34
34
|
expect(value).to eq id
|
35
35
|
end
|
36
36
|
|
37
37
|
it "includes issue_instant in the saml:LogoutRequest attributes" do
|
38
|
-
value = xml.
|
38
|
+
value = xml.at_xpath('/samlp:LogoutResponse', Onelogin::NAMESPACES)['IssueInstant']
|
39
39
|
expect(value).to eq issue_instant
|
40
40
|
end
|
41
41
|
|
42
42
|
it "includes in_response_to in the saml:LogoutRequest attributes" do
|
43
|
-
value = xml.
|
43
|
+
value = xml.at_xpath('/samlp:LogoutResponse', Onelogin::NAMESPACES)['InResponseTo']
|
44
44
|
expect(value).to eq in_response_to
|
45
45
|
end
|
46
46
|
|
47
47
|
it "includes issuer tag" do
|
48
|
-
value = xml.
|
48
|
+
value = xml.at_xpath("/samlp:LogoutResponse/saml:Issuer", Onelogin::NAMESPACES).content
|
49
49
|
expect(value).to eq issuer
|
50
50
|
end
|
51
51
|
|
52
52
|
it "includes status code tag" do
|
53
|
-
value = xml.
|
53
|
+
value = xml.at_xpath("/samlp:LogoutResponse/samlp:Status/samlp:StatusCode", Onelogin::NAMESPACES)['Value']
|
54
54
|
expect(value).to eq Onelogin::Saml::StatusCodes::SUCCESS_URI
|
55
55
|
end
|
56
56
|
|
57
57
|
it "includes status message tag" do
|
58
|
-
value = xml.
|
58
|
+
value = xml.at_xpath("/samlp:LogoutResponse/samlp:Status/samlp:StatusMessage", Onelogin::NAMESPACES).content
|
59
59
|
expect(value).to eq Onelogin::Saml::LogoutResponse::STATUS_MESSAGE
|
60
60
|
end
|
61
61
|
|
data/spec/meta_data_spec.rb
CHANGED
@@ -32,7 +32,7 @@ describe Onelogin::Saml::MetaData do
|
|
32
32
|
)
|
33
33
|
doc = REXML::Document.new Onelogin::Saml::MetaData.create(settings)
|
34
34
|
key_descriptors = REXML::XPath.match(doc, "//KeyDescriptor")
|
35
|
-
key_descriptors.should
|
35
|
+
key_descriptors.length.should == 2
|
36
36
|
key_descriptors[0].attributes["use"].should == "encryption"
|
37
37
|
key_descriptors[1].attributes["use"].should == "signing"
|
38
38
|
end
|
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.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OneLogin LLC
|
@@ -14,22 +14,22 @@ authors:
|
|
14
14
|
autorequire:
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
|
-
date: 2015-
|
17
|
+
date: 2015-08-03 00:00:00.000000000 Z
|
18
18
|
dependencies:
|
19
19
|
- !ruby/object:Gem::Dependency
|
20
|
-
name:
|
20
|
+
name: nokogiri
|
21
21
|
requirement: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
|
-
- - "
|
23
|
+
- - "~>"
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version:
|
25
|
+
version: '1.6'
|
26
26
|
type: :runtime
|
27
27
|
prerelease: false
|
28
28
|
version_requirements: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- - "
|
30
|
+
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: '1.6'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: ffi
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|