saml_tools 0.0.1 → 0.1.0
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 +5 -13
- data/README.rdoc +21 -2
- data/lib/saml_tool/certificate.rb +8 -7
- data/lib/saml_tool/decoder.rb +1 -1
- data/lib/saml_tool/encoder.rb +1 -1
- data/lib/saml_tool/erb_builder.rb +10 -1
- data/lib/saml_tool/reader.rb +11 -3
- data/lib/saml_tool/redirect.rb +11 -0
- data/lib/saml_tool/response_reader.rb +37 -19
- data/lib/saml_tool/rsa_key.rb +4 -3
- data/lib/saml_tool/saml.rb +5 -5
- data/lib/saml_tool/settings.rb +3 -2
- data/lib/saml_tool/validator.rb +2 -1
- data/lib/saml_tool/version.rb +3 -1
- data/test/files/response_simple_attributes.xml +30 -0
- data/test/test_helper.rb +11 -7
- data/test/units/saml_tool/response_reader_test.rb +43 -23
- metadata +29 -27
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZjE1NGRlYzdhMmQzZDg4N2ZiMTZlY2RkZGFjZWViMDNlOWJkOWI5Ng==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cca6a06834de7176a2a91089e9fc3faf3bb67f86
|
4
|
+
data.tar.gz: a922aa5824ce9cf41cb5c044284559f61777aac4
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
NTNlNzY4ODM0MDZmNjg0MGRkOTdhMDIxYjEwYWRhNjUyMTBmZDRlMjNkNGM4
|
11
|
-
NzQ2OThjZDcxN2NmNjVkZTM1MTFhNDZjMzk5OGIzN2RlOWI3ODE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZWY0OTc2Y2JiODhlYjIwYjdmY2Y2ZDhkM2Y4MjEzYThiMDAxY2YyNWNmODBl
|
14
|
-
ZjVlNWMxZWVlOWM3NTc1YjZkNjM1ZmQyODQxNjE5YzQ4M2UxZTMzOTUxOWIw
|
15
|
-
YWUwNjg2ZDk3MDNiNDg5NjFmMmRhYzA4Y2Y4NDVlNWYyNDI2MDI=
|
6
|
+
metadata.gz: 4d61deec4411bd06cabef1f18ba17a794888eece5581ac6dda4ab92d15c77d42f0a4c3d0917ffe6e63dab394bb20365ef966d6476394f3864d41168c53daa62c
|
7
|
+
data.tar.gz: 6ba8be4feae23224a20a9e4d5ad712a78f92ab326368959dba893a7980414a15c8a63052eabc466cc914ae26be1b823753744e35eefc70ae25b05e637b641929
|
data/README.rdoc
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
=SAML Tools
|
2
2
|
|
3
|
-
Tools to simplify the creation, validation and sending of SAML objects
|
3
|
+
Tools to simplify the creation, validation and sending of SAML objects.
|
4
|
+
|
5
|
+
These tools are available as a gem:
|
6
|
+
|
7
|
+
gem 'saml_tools'
|
4
8
|
|
5
9
|
== SamlTool::Certificate
|
6
10
|
Version of OpenSSL::X509::Certificate that adds methods to simplify the retrieval
|
@@ -62,4 +66,19 @@ Compares documents with SAML schemas to test if they have a valid structure.
|
|
62
66
|
== Further reading
|
63
67
|
|
64
68
|
I've {blogged here}[http://undervale.co.uk/blog/?p=490] about some of highs and
|
65
|
-
lows of building these tools.
|
69
|
+
lows of building these tools.
|
70
|
+
|
71
|
+
There is a demo app that I have been working with as I've developed these tools:
|
72
|
+
|
73
|
+
https://github.com/warwickshire/saml_tools_demo
|
74
|
+
|
75
|
+
This work has been greatly influenced by:
|
76
|
+
|
77
|
+
* https://github.com/onelogin/ruby-saml
|
78
|
+
* https://onelogin.zendesk.com/hc/en-us/articles/201175674-SAML-toolkit-for-Ruby-on-Rails
|
79
|
+
* http://samltool-j.appspot.com/saml_demo.jsp
|
80
|
+
* https://www.oasis-open.org/committees/documents.php?wg_abbrev=security
|
81
|
+
* http://en.wikipedia.org/wiki/SAML_2.0
|
82
|
+
* https://github.com/lawrencepit/ruby-saml-idp
|
83
|
+
* http://users.dcc.uchile.cl/~pcamacho/tutorial/web/xmlsec/xmlsec.html
|
84
|
+
* https://github.com/digidentity/libsaml
|
@@ -1,27 +1,28 @@
|
|
1
|
-
|
1
|
+
# Version of OpenSSL::X509::Certificate that adds methods to simplify the retrieval
|
2
|
+
# of data used in SAML responses.
|
2
3
|
module SamlTool
|
3
4
|
class Certificate < OpenSSL::X509::Certificate
|
4
|
-
|
5
|
+
|
5
6
|
alias_method :serial_number, :serial
|
6
|
-
|
7
|
+
|
7
8
|
def without_leading_and_trailing_labels
|
8
9
|
to_s.lines.to_a[1..-2].join
|
9
10
|
end
|
10
11
|
alias_method :x509_certificate, :without_leading_and_trailing_labels
|
11
|
-
|
12
|
+
|
12
13
|
def issuer_name
|
13
14
|
@issuer_name ||= slash_list_to_comma_list(issuer)
|
14
15
|
end
|
15
|
-
|
16
|
+
|
16
17
|
def subject_name
|
17
18
|
@subject_name ||= slash_list_to_comma_list(subject)
|
18
19
|
end
|
19
|
-
|
20
|
+
|
20
21
|
def slash_list_to_comma_list(string)
|
21
22
|
string = string.to_s
|
22
23
|
string = string[1..-1] if string[0] == '/'
|
23
24
|
string.split('/').reverse.join(',')
|
24
25
|
end
|
25
|
-
|
26
|
+
|
26
27
|
end
|
27
28
|
end
|
data/lib/saml_tool/decoder.rb
CHANGED
data/lib/saml_tool/encoder.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
require 'erb'
|
2
|
+
|
3
|
+
# Used to build SAML content from erb templates.
|
4
|
+
#
|
5
|
+
# output = SamlTool::ErbBuilder.build(
|
6
|
+
# template: '<foo><%= settings %></foo>',
|
7
|
+
# settings: 'bar'
|
8
|
+
# )
|
9
|
+
# output == '<foo>bar</foo>'
|
10
|
+
#
|
2
11
|
module SamlTool
|
3
12
|
class ErbBuilder
|
4
|
-
|
13
|
+
|
5
14
|
attr_reader :args, :settings, :template
|
6
15
|
|
7
16
|
def self.build(args)
|
data/lib/saml_tool/reader.rb
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
|
1
|
+
# Wraps SAML documents and exposes data via methods
|
2
|
+
#
|
3
|
+
# output == '<foo>bar</foo>'
|
4
|
+
# reader = SamlTool::Reader.new(
|
5
|
+
# output,
|
6
|
+
# {foo: '//foo/text()'}
|
7
|
+
# )
|
8
|
+
# reader.foo == 'bar'
|
9
|
+
#
|
2
10
|
module SamlTool
|
3
11
|
class Reader
|
4
12
|
attr_reader :saml, :config, :namespaces
|
@@ -23,12 +31,12 @@ module SamlTool
|
|
23
31
|
instance_variable_set("@#{key}".to_sym, content)
|
24
32
|
end
|
25
33
|
end
|
26
|
-
|
34
|
+
|
27
35
|
# A string with memory of the element that was the source of its content.
|
28
36
|
# Typically, the source will be a Nokogiri::XML::NodeSet. So:
|
29
37
|
# content --> text from an element.
|
30
38
|
# content.source --> the Nokogiri NodeSet the text was extracted from.
|
31
|
-
class Content < String
|
39
|
+
class Content < String
|
32
40
|
attr_reader :source
|
33
41
|
def initialize(source)
|
34
42
|
@source = source
|
data/lib/saml_tool/redirect.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
require 'uri'
|
2
2
|
require 'cgi'
|
3
|
+
|
4
|
+
# Used to construct redirection uris
|
5
|
+
#
|
6
|
+
# redirect = Redirect.uri(
|
7
|
+
# to: 'http://example.com',
|
8
|
+
# data: {
|
9
|
+
# foo: 'bar'
|
10
|
+
# }
|
11
|
+
# )
|
12
|
+
# redirect == "http://example.com?foo=bar"
|
13
|
+
#
|
3
14
|
module SamlTool
|
4
15
|
|
5
16
|
class Redirect
|
@@ -1,8 +1,11 @@
|
|
1
1
|
require "openssl"
|
2
2
|
|
3
|
+
# A version of SamlTool::Reader tailored for handling SAML responses. It includes
|
4
|
+
# a valid? method that validates the SAML structure and checks the signature is
|
5
|
+
# correct.
|
3
6
|
module SamlTool
|
4
7
|
class ResponseReader < Reader
|
5
|
-
|
8
|
+
|
6
9
|
# On creation, the keys for this hash will be converted into methods that
|
7
10
|
# will return the text gathered at the xpath in the matching value.
|
8
11
|
def default_config
|
@@ -17,9 +20,9 @@ module SamlTool
|
|
17
20
|
signature_algorithm: '//ds:SignatureMethod/@Algorithm',
|
18
21
|
signed_info: '//ds:SignedInfo'
|
19
22
|
}
|
20
|
-
end
|
21
|
-
|
22
|
-
def initialize(saml, config = {}, namespaces = {})
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(saml, config = {}, namespaces = {})
|
23
26
|
super(
|
24
27
|
saml,
|
25
28
|
config.merge(default_config),
|
@@ -27,6 +30,21 @@ module SamlTool
|
|
27
30
|
)
|
28
31
|
end
|
29
32
|
|
33
|
+
def attribute_names
|
34
|
+
@attribute_names ||= saml.xpath("//saml:Attribute/@Name").collect(&:value)
|
35
|
+
end
|
36
|
+
|
37
|
+
# A hash with the attribute names as keys, and the matching attribute value content as values.
|
38
|
+
# Note that if the same Name is assigned to more than one attribute or an attribute contains more than
|
39
|
+
# one value, then the value for that key will be an array.
|
40
|
+
def attributes
|
41
|
+
@attributes ||= attribute_names.inject({}) do |hash, name|
|
42
|
+
attribute_values = saml.xpath("//saml:Attribute[@Name='#{name}']/saml:AttributeValue/text()")
|
43
|
+
hash[name] = attribute_values.length > 1 ? attribute_values.collect(&:to_s) : attribute_values.to_s
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
30
48
|
def valid?
|
31
49
|
structurally_valid? && signature_verified? && digests_match?
|
32
50
|
end
|
@@ -46,19 +64,19 @@ module SamlTool
|
|
46
64
|
def digests_match?
|
47
65
|
digest_hash == decoded_digest_value
|
48
66
|
end
|
49
|
-
|
67
|
+
|
50
68
|
def signatureless
|
51
69
|
@signatureless ||= clone_saml_and_remove_signature
|
52
70
|
end
|
53
|
-
|
71
|
+
|
54
72
|
def certificate
|
55
73
|
@certificate ||= OpenSSL::X509::Certificate.new(raw_cert)
|
56
74
|
end
|
57
|
-
|
75
|
+
|
58
76
|
def raw_cert
|
59
77
|
@raw_cert ||= Base64.decode64(base64_cert)
|
60
78
|
end
|
61
|
-
|
79
|
+
|
62
80
|
def fingerprint
|
63
81
|
@fingerprint ||= Digest::SHA1.hexdigest(certificate.to_der)
|
64
82
|
end
|
@@ -66,7 +84,7 @@ module SamlTool
|
|
66
84
|
def signature
|
67
85
|
@signature ||= Base64.decode64(signature_value)
|
68
86
|
end
|
69
|
-
|
87
|
+
|
70
88
|
def canonicalization_algorithm
|
71
89
|
case canonicalization_method
|
72
90
|
when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then Nokogiri::XML::XML_C14N_1_0
|
@@ -74,14 +92,14 @@ module SamlTool
|
|
74
92
|
else Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
|
75
93
|
end
|
76
94
|
end
|
77
|
-
|
95
|
+
|
78
96
|
def hashed_element
|
79
97
|
@hashed_element ||= signatureless.at_xpath("//*[@ID='#{reference_uri[1..-1]}']")
|
80
98
|
end
|
81
|
-
|
99
|
+
|
82
100
|
def canonicalized_hashed_element
|
83
101
|
hashed_element.canonicalize(
|
84
|
-
canonicalization_algorithm,
|
102
|
+
canonicalization_algorithm,
|
85
103
|
inclusive_namespaces.split(' ')
|
86
104
|
)
|
87
105
|
end
|
@@ -96,7 +114,7 @@ module SamlTool
|
|
96
114
|
def signed_info_element
|
97
115
|
signed_info.source.first
|
98
116
|
end
|
99
|
-
|
117
|
+
|
100
118
|
def digest_algorithm_class
|
101
119
|
@digest_algorithm_class ||= determine_algorithm_class(digest_algorithm)
|
102
120
|
end
|
@@ -104,7 +122,7 @@ module SamlTool
|
|
104
122
|
def signature_algorithm_class
|
105
123
|
@signature_algorithm_class ||= determine_algorithm_class(signature_algorithm)
|
106
124
|
end
|
107
|
-
|
125
|
+
|
108
126
|
def determine_algorithm_class(method_text)
|
109
127
|
case method_text.slice(/sha(\d+)\s*$/, 1)
|
110
128
|
when '256' then OpenSSL::Digest::SHA256
|
@@ -114,11 +132,11 @@ module SamlTool
|
|
114
132
|
OpenSSL::Digest::SHA1
|
115
133
|
end
|
116
134
|
end
|
117
|
-
|
135
|
+
|
118
136
|
def digest_hash
|
119
137
|
@digest_hash ||= digest_algorithm_class.digest(canonicalized_hashed_element)
|
120
138
|
end
|
121
|
-
|
139
|
+
|
122
140
|
def decoded_digest_value
|
123
141
|
Base64.decode64(digest_value)
|
124
142
|
end
|
@@ -128,18 +146,18 @@ module SamlTool
|
|
128
146
|
cloned_saml.xpath('//ds:Signature', namespaces).remove
|
129
147
|
return SamlTool::SAML(cloned_saml.to_s)
|
130
148
|
end
|
131
|
-
|
149
|
+
|
132
150
|
def default_namespaces
|
133
151
|
{
|
134
152
|
ds: dsig,
|
135
153
|
ec: c14m
|
136
154
|
}
|
137
155
|
end
|
138
|
-
|
156
|
+
|
139
157
|
def c14m
|
140
158
|
'http://www.w3.org/2001/10/xml-exc-c14n#'
|
141
159
|
end
|
142
|
-
|
160
|
+
|
143
161
|
def dsig
|
144
162
|
'http://www.w3.org/2000/09/xmldsig#'
|
145
163
|
end
|
data/lib/saml_tool/rsa_key.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
|
1
|
+
# Version of OpenSSL::PKey::RSA that adds methods to simplify the retrieval
|
2
|
+
# of data used in SAML responses.
|
2
3
|
module SamlTool
|
3
4
|
class RsaKey < OpenSSL::PKey::RSA
|
4
|
-
|
5
|
+
|
5
6
|
def modulus
|
6
7
|
Base64.encode64(n.to_s(2))
|
7
8
|
end
|
8
|
-
|
9
|
+
|
9
10
|
def exponent
|
10
11
|
Base64.encode64(e.to_s(2))
|
11
12
|
end
|
data/lib/saml_tool/saml.rb
CHANGED
@@ -7,24 +7,24 @@ module SamlTool
|
|
7
7
|
SAML::Document.parse(thing, url, encoding, options, &block)
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
# A wrapper for Nokogiri::XML, that applies defaults that are appropriate for SAML
|
12
12
|
module SAML
|
13
|
-
|
13
|
+
|
14
14
|
class ParseOptions < Nokogiri::XML::ParseOptions
|
15
15
|
DEFAULT_SAML = STRICT
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
class Document < Nokogiri::XML::Document
|
19
19
|
def self.parse string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_SAML, &block
|
20
20
|
super
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
# Parse XML. Convenience method for Nokogiri::XML::Document.parse
|
25
25
|
def self.parse thing, url = nil, encoding = nil, options = ParseOptions::DEFAULT_SAML, &block
|
26
26
|
Document.parse(thing, url, encoding, options, &block)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
end
|
30
30
|
end
|
data/lib/saml_tool/settings.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
require 'time'
|
3
|
+
# Packages up settings so that they can be more easily passed to other objects.
|
3
4
|
module SamlTool
|
4
5
|
class Settings < Hashie::Mash
|
5
6
|
|
@@ -10,12 +11,12 @@ module SamlTool
|
|
10
11
|
def issue_instance
|
11
12
|
fetch :issue_instance, auto_issue_instance
|
12
13
|
end
|
13
|
-
|
14
|
+
|
14
15
|
private
|
15
16
|
def auto_uuid
|
16
17
|
@auto_uuid ||= ('_' + SecureRandom.uuid)
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
def auto_issue_instance
|
20
21
|
@auto_issue_instance ||= Time.now.utc.iso8601
|
21
22
|
end
|
data/lib/saml_tool/validator.rb
CHANGED
data/lib/saml_tool/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
|
3
|
+
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
|
4
|
+
ID="GOSAMLR12901174571794"
|
5
|
+
Version="2.0"
|
6
|
+
IssueInstant="issue_instance"
|
7
|
+
Destination="{recipient}">
|
8
|
+
<saml:Assertion xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
9
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
10
|
+
Version="2.0"
|
11
|
+
ID="GOSAMLR12901174571794">
|
12
|
+
<saml:AttributeStatement>
|
13
|
+
<saml:Attribute Name="One">
|
14
|
+
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
15
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
16
|
+
xsi:type="xs:string">1</saml:AttributeValue>
|
17
|
+
</saml:Attribute>
|
18
|
+
<saml:Attribute Name="Two">
|
19
|
+
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
20
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
21
|
+
xsi:type="xs:string">2</saml:AttributeValue>
|
22
|
+
</saml:Attribute>
|
23
|
+
<saml:Attribute Name="Three">
|
24
|
+
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
25
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
26
|
+
xsi:type="xs:string">3</saml:AttributeValue>
|
27
|
+
</saml:Attribute>
|
28
|
+
</saml:AttributeStatement>
|
29
|
+
</saml:Assertion>
|
30
|
+
</samlp:Response>
|
data/test/test_helper.rb
CHANGED
@@ -5,7 +5,7 @@ require 'minitest/autorun'
|
|
5
5
|
require 'saml_tool'
|
6
6
|
|
7
7
|
class Minitest::Test
|
8
|
-
|
8
|
+
|
9
9
|
def valid_xml
|
10
10
|
'<foo>bar</foo>'
|
11
11
|
end
|
@@ -21,25 +21,29 @@ class Minitest::Test
|
|
21
21
|
def request_saml_erb
|
22
22
|
contents_of 'files/request.saml.erb'
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def response_xml
|
26
26
|
contents_of 'files/response.xml'
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def open_saml_request
|
30
30
|
contents_of 'files/open_saml_response.xml'
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
|
+
def response_simple_attributes
|
34
|
+
contents_of 'files/response_simple_attributes.xml'
|
35
|
+
end
|
36
|
+
|
33
37
|
def x509_certificate
|
34
38
|
@x509_certificate ||= OpenSSL::PKCS12.new(
|
35
|
-
contents_of('files/usercert.p12'),
|
39
|
+
contents_of('files/usercert.p12'),
|
36
40
|
'hello'
|
37
41
|
).certificate
|
38
42
|
end
|
39
|
-
|
43
|
+
|
40
44
|
def open_ssl_rsa_key
|
41
45
|
@open_ssl_rsa_key ||= OpenSSL::PKey::RSA.new(
|
42
|
-
contents_of('files/userkey.pem'),
|
46
|
+
contents_of('files/userkey.pem'),
|
43
47
|
'hello'
|
44
48
|
)
|
45
49
|
end
|
@@ -2,85 +2,85 @@ require_relative '../../test_helper'
|
|
2
2
|
|
3
3
|
module SamlTool
|
4
4
|
class ResponseReaderTest < Minitest::Test
|
5
|
-
|
5
|
+
|
6
6
|
def test_saml
|
7
7
|
assert_kind_of SAML::Document, response_document.saml
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def test_signatureless
|
11
11
|
assert_kind_of SAML::Document, response_document.signatureless
|
12
12
|
expected = response_document.saml.clone
|
13
13
|
expected.xpath('//ds:Signature', { 'ds' => dsig }).remove
|
14
14
|
assert_equal expected.to_s, response_document.signatureless.to_s
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def test_signatureless_does_not_impact_saml
|
18
18
|
response_document.signatureless
|
19
19
|
assert response_document.saml.to_s != response_document.signatureless.to_s, 'Changes made in forming signatureless should not also happen to saml'
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def test_base64_cert
|
23
23
|
base64_cert = response_document_saml.xpath('//ds:X509Certificate/text()', { 'ds' => dsig })
|
24
24
|
assert_equal base64_cert.to_s, response_document.base64_cert
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def test_certificate
|
28
28
|
assert_kind_of OpenSSL::X509::Certificate, response_document.certificate
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def test_fingerprint
|
32
32
|
expected = Digest::SHA1.hexdigest(response_document.certificate.to_der)
|
33
33
|
assert_equal expected, response_document.fingerprint
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
def test_canonicalization_method
|
37
37
|
expected = response_document_saml.xpath('//ds:CanonicalizationMethod/@Algorithm', { 'ds' => dsig })
|
38
38
|
assert_equal expected.to_s, response_document.canonicalization_method
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def test_canonicalization_algorithm
|
42
42
|
expected = Nokogiri::XML::XML_C14N_1_0
|
43
43
|
assert_equal expected, response_document.canonicalization_algorithm
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
def test_reference_uri
|
47
47
|
expected = response_document_saml.xpath('//ds:Reference/@URI', { 'ds' => dsig })
|
48
48
|
assert_equal expected.to_s, response_document.reference_uri
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
def test_inclusive_namespaces
|
52
52
|
assert_equal "", response_document.inclusive_namespaces
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def test_inclusive_namespaces_when_they_exist_in_saml
|
56
56
|
document = ResponseReader.new(open_saml_request)
|
57
57
|
assert_equal 'xs', document.inclusive_namespaces
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def test_hashed_element
|
61
61
|
remove_signature_from_assertion
|
62
62
|
assert_equal assertion.to_s, response_document.hashed_element.to_s
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
def test_canonicalized_hashed_element
|
66
66
|
remove_signature_from_assertion
|
67
67
|
expected = assertion.canonicalize(Nokogiri::XML::XML_C14N_1_0, [])
|
68
68
|
assert_equal expected, response_document.canonicalized_hashed_element
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
def test_digest_algorithm
|
72
72
|
assert_equal 'http://www.w3.org/2000/09/xmldsig#sha1', response_document.digest_algorithm
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
def test_digest_algorithm_class
|
76
76
|
assert_equal OpenSSL::Digest::SHA1, response_document.digest_algorithm_class
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
def test_digest_hash
|
80
80
|
expected = OpenSSL::Digest::SHA1.digest(response_document.canonicalized_hashed_element)
|
81
81
|
assert_equal expected, response_document.digest_hash
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
def test_digest_hash_matches_digest_value
|
85
85
|
assert_equal response_document.digest_hash, response_document.decoded_digest_value
|
86
86
|
end
|
@@ -112,6 +112,22 @@ module SamlTool
|
|
112
112
|
assert_equal true, response_document.structurally_valid?
|
113
113
|
end
|
114
114
|
|
115
|
+
def test_attribute_names
|
116
|
+
with_simple_attributes
|
117
|
+
assert_equal %w{One Two Three}, response_document.attribute_names
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_attributes
|
121
|
+
with_simple_attributes
|
122
|
+
expected = {'One' => '1', 'Two' => '2', 'Three' => '3'}
|
123
|
+
assert_equal expected, response_document.attributes
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_attributes_with_complicated_structure
|
127
|
+
expected = {"uid"=>"demo", "another_value"=>["value1", "value2"], "role"=>["role1", "role2"]}
|
128
|
+
assert_equal expected, response_document.attributes
|
129
|
+
end
|
130
|
+
|
115
131
|
def test_valid
|
116
132
|
assert_equal true, response_document.valid?
|
117
133
|
end
|
@@ -119,26 +135,30 @@ module SamlTool
|
|
119
135
|
def response_document
|
120
136
|
@response_document ||= ResponseReader.new(response_xml)
|
121
137
|
end
|
122
|
-
|
138
|
+
|
139
|
+
def with_simple_attributes
|
140
|
+
@response_document = ResponseReader.new(response_simple_attributes)
|
141
|
+
end
|
142
|
+
|
123
143
|
def assertion
|
124
144
|
@assertion ||= response_document_saml.at_xpath('//saml:Assertion')
|
125
145
|
end
|
126
|
-
|
146
|
+
|
127
147
|
def remove_signature_from_assertion
|
128
148
|
assertion.xpath('//ds:Signature', { 'ds' => dsig }).remove
|
129
149
|
end
|
130
|
-
|
150
|
+
|
131
151
|
def response_document_saml
|
132
152
|
@response_document_saml ||= SamlTool::SAML(response_xml)
|
133
153
|
end
|
134
|
-
|
154
|
+
|
135
155
|
def c14m
|
136
156
|
'http://www.w3.org/2001/10/xml-exc-c14n#'
|
137
157
|
end
|
138
|
-
|
158
|
+
|
139
159
|
def dsig
|
140
160
|
'http://www.w3.org/2000/09/xmldsig#'
|
141
161
|
end
|
142
|
-
|
162
|
+
|
143
163
|
end
|
144
164
|
end
|
metadata
CHANGED
@@ -1,77 +1,77 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saml_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Nichols
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: hashie
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: xmldsig
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '5.1'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '5.1'
|
69
|
-
description:
|
69
|
+
description: " SAML 2.0 is an XML-based protocol that uses security tokens containing
|
70
70
|
assertions to pass information about a principal (usually an end user) between a
|
71
71
|
SAML authority, that is, an identity provider, and a SAML consumer, that is, a service
|
72
72
|
provider. SAML 2.0 enables web-based authentication and authorization scenarios
|
73
73
|
including cross-domain single sign-on (SSO), which helps reduce the administrative
|
74
|
-
overhead of distributing multiple authentication tokens to the user.
|
74
|
+
overhead of distributing multiple authentication tokens to the user."
|
75
75
|
email:
|
76
76
|
- rob@undervale.co.uk
|
77
77
|
executables: []
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- test/files/open_saml_response.xml
|
105
105
|
- test/files/request.saml.erb
|
106
106
|
- test/files/response.xml
|
107
|
+
- test/files/response_simple_attributes.xml
|
107
108
|
- test/files/response_template.xml
|
108
109
|
- test/files/usercert.p12
|
109
110
|
- test/files/userkey.pem
|
@@ -130,39 +131,40 @@ require_paths:
|
|
130
131
|
- lib
|
131
132
|
required_ruby_version: !ruby/object:Gem::Requirement
|
132
133
|
requirements:
|
133
|
-
- -
|
134
|
+
- - ">="
|
134
135
|
- !ruby/object:Gem::Version
|
135
136
|
version: '0'
|
136
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
138
|
requirements:
|
138
|
-
- -
|
139
|
+
- - ">="
|
139
140
|
- !ruby/object:Gem::Version
|
140
141
|
version: '0'
|
141
142
|
requirements: []
|
142
143
|
rubyforge_project:
|
143
|
-
rubygems_version: 2.
|
144
|
+
rubygems_version: 2.5.1
|
144
145
|
signing_key:
|
145
146
|
specification_version: 4
|
146
147
|
summary: Tools to simplify the creation, validation and sending of SAML objects
|
147
148
|
test_files:
|
148
149
|
- test/files/TEST_FILES.rdoc
|
149
|
-
- test/files/response.xml
|
150
|
-
- test/files/valid_saml_request.xml
|
151
150
|
- test/files/open_saml_response.xml
|
152
|
-
- test/files/
|
151
|
+
- test/files/response_simple_attributes.xml
|
153
152
|
- test/files/usercert.p12
|
154
|
-
- test/files/request.saml.erb
|
155
|
-
- test/files/cacert.pem
|
156
153
|
- test/files/userkey.pem
|
157
|
-
- test/
|
158
|
-
- test/
|
154
|
+
- test/files/cacert.pem
|
155
|
+
- test/files/valid_saml_request.xml
|
156
|
+
- test/files/response_template.xml
|
157
|
+
- test/files/request.saml.erb
|
158
|
+
- test/files/response.xml
|
159
159
|
- test/units/saml_tool/response_reader_test.rb
|
160
|
-
- test/units/saml_tool/saml_test.rb
|
161
160
|
- test/units/saml_tool/erb_builder_test.rb
|
162
|
-
- test/units/saml_tool/
|
163
|
-
- test/units/saml_tool/rsa_key_test.rb
|
164
|
-
- test/units/saml_tool/certificate_test.rb
|
161
|
+
- test/units/saml_tool/saml_test.rb
|
165
162
|
- test/units/saml_tool/encoder_test.rb
|
166
|
-
- test/units/saml_tool/
|
163
|
+
- test/units/saml_tool/reader_test.rb
|
164
|
+
- test/units/saml_tool/certificate_test.rb
|
165
|
+
- test/units/saml_tool/validator_test.rb
|
166
|
+
- test/units/saml_tool/redirect_test.rb
|
167
167
|
- test/units/saml_tool/settings_test.rb
|
168
|
+
- test/units/saml_tool/decoder_test.rb
|
169
|
+
- test/units/saml_tool/rsa_key_test.rb
|
168
170
|
- test/test_helper.rb
|