saml_tools 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|