ruby-saml 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- data/.gitignore +5 -0
- data/.travis.yml +5 -0
- data/Gemfile +10 -6
- data/{README.rdoc → README.md} +31 -26
- data/lib/onelogin/ruby-saml/authrequest.rb +23 -18
- data/lib/onelogin/ruby-saml/logging.rb +4 -0
- data/lib/onelogin/ruby-saml/logoutrequest.rb +80 -0
- data/lib/onelogin/ruby-saml/response.rb +38 -4
- data/lib/onelogin/ruby-saml/settings.rb +10 -1
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +1 -0
- data/lib/schemas/saml20assertion_schema.xsd +283 -0
- data/lib/schemas/saml20protocol_schema.xsd +302 -0
- data/lib/schemas/xenc_schema.xsd +146 -0
- data/lib/schemas/xmldsig_schema.xsd +318 -0
- data/lib/xml_security.rb +52 -36
- data/ruby-saml.gemspec +4 -26
- data/test/logoutrequest_test.rb +98 -0
- data/test/response_test.rb +40 -2
- data/test/responses/adfs_response_sha1.xml +46 -0
- data/test/responses/{adfs_response.xml → adfs_response_sha256.xml} +0 -0
- data/test/responses/adfs_response_sha384.xml +46 -0
- data/test/responses/adfs_response_sha512.xml +46 -0
- data/test/responses/no_signature_ns.xml +48 -0
- data/test/settings_test.rb +22 -2
- data/test/test_helper.rb +2 -0
- data/test/xml_security_test.rb +103 -4
- metadata +79 -105
- data/Gemfile.lock +0 -38
data/lib/xml_security.rb
CHANGED
@@ -26,7 +26,7 @@ require 'rubygems'
|
|
26
26
|
require "rexml/document"
|
27
27
|
require "rexml/xpath"
|
28
28
|
require "openssl"
|
29
|
-
require
|
29
|
+
require 'nokogiri'
|
30
30
|
require "digest/sha1"
|
31
31
|
require "digest/sha2"
|
32
32
|
require "onelogin/ruby-saml/validation_error"
|
@@ -34,9 +34,10 @@ require "onelogin/ruby-saml/validation_error"
|
|
34
34
|
module XMLSecurity
|
35
35
|
|
36
36
|
class SignedDocument < REXML::Document
|
37
|
+
C14N = "http://www.w3.org/2001/10/xml-exc-c14n#"
|
37
38
|
DSIG = "http://www.w3.org/2000/09/xmldsig#"
|
38
39
|
|
39
|
-
attr_accessor :signed_element_id
|
40
|
+
attr_accessor :signed_element_id, :sig_element, :noko_sig_element
|
40
41
|
|
41
42
|
def initialize(response)
|
42
43
|
super(response)
|
@@ -45,9 +46,10 @@ module XMLSecurity
|
|
45
46
|
|
46
47
|
def validate(idp_cert_fingerprint, soft = true)
|
47
48
|
# get cert from response
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
cert_element = REXML::XPath.first(self, "//ds:X509Certificate", { "ds"=>DSIG })
|
50
|
+
base64_cert = cert_element.text
|
51
|
+
cert_text = Base64.decode64(base64_cert)
|
52
|
+
cert = OpenSSL::X509::Certificate.new(cert_text)
|
51
53
|
|
52
54
|
# check cert matches registered idp cert
|
53
55
|
fingerprint = Digest::SHA1.hexdigest(cert.to_der)
|
@@ -63,40 +65,43 @@ module XMLSecurity
|
|
63
65
|
# validate references
|
64
66
|
|
65
67
|
# check for inclusive namespaces
|
68
|
+
inclusive_namespaces = extract_inclusive_namespaces
|
66
69
|
|
67
|
-
|
68
|
-
inclusive_namespace_element = REXML::XPath.first(self, "//ec:InclusiveNamespaces")
|
70
|
+
document = Nokogiri.parse(self.to_s)
|
69
71
|
|
70
|
-
|
71
|
-
|
72
|
-
|
72
|
+
# store and remove signature node
|
73
|
+
self.sig_element ||= begin
|
74
|
+
element = REXML::XPath.first(self, "//ds:Signature", {"ds"=>DSIG})
|
75
|
+
element.remove
|
73
76
|
end
|
74
77
|
|
75
|
-
|
76
|
-
|
77
|
-
sig_element
|
78
|
+
|
79
|
+
# verify signature
|
80
|
+
signed_info_element = REXML::XPath.first(sig_element, "//ds:SignedInfo", {"ds"=>DSIG})
|
81
|
+
self.noko_sig_element ||= document.at_xpath('//ds:Signature', 'ds' => DSIG)
|
82
|
+
noko_signed_info_element = noko_sig_element.at_xpath('./ds:SignedInfo', 'ds' => DSIG)
|
83
|
+
canon_algorithm = canon_algorithm REXML::XPath.first(sig_element, '//ds:CanonicalizationMethod')
|
84
|
+
canon_string = noko_signed_info_element.canonicalize(canon_algorithm)
|
85
|
+
noko_sig_element.remove
|
78
86
|
|
79
87
|
# check digests
|
80
88
|
REXML::XPath.each(sig_element, "//ds:Reference", {"ds"=>DSIG}) do |ref|
|
81
89
|
uri = ref.attributes.get_attribute("URI").value
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
canon_hashed_element =
|
86
|
-
|
87
|
-
|
88
|
-
|
90
|
+
|
91
|
+
hashed_element = document.at_xpath("//*[@ID='#{uri[1..-1]}']")
|
92
|
+
canon_algorithm = canon_algorithm REXML::XPath.first(ref, '//ds:CanonicalizationMethod')
|
93
|
+
canon_hashed_element = hashed_element.canonicalize(canon_algorithm, inclusive_namespaces).gsub('&','&')
|
94
|
+
|
95
|
+
digest_algorithm = algorithm(REXML::XPath.first(ref, "//ds:DigestMethod"))
|
96
|
+
|
97
|
+
hash = digest_algorithm.digest(canon_hashed_element)
|
98
|
+
digest_value = Base64.decode64(REXML::XPath.first(ref, "//ds:DigestValue", {"ds"=>DSIG}).text)
|
89
99
|
|
90
100
|
unless digests_match?(hash, digest_value)
|
91
101
|
return soft ? false : (raise Onelogin::Saml::ValidationError.new("Digest mismatch"))
|
92
102
|
end
|
93
103
|
end
|
94
104
|
|
95
|
-
# verify signature
|
96
|
-
canoner = XML::Util::XmlCanonicalizer.new(false, true)
|
97
|
-
signed_info_element = REXML::XPath.first(sig_element, "//ds:SignedInfo", {"ds"=>DSIG})
|
98
|
-
canon_string = canoner.canonicalize(signed_info_element)
|
99
|
-
|
100
105
|
base64_signature = REXML::XPath.first(sig_element, "//ds:SignatureValue", {"ds"=>DSIG}).text
|
101
106
|
signature = Base64.decode64(base64_signature)
|
102
107
|
|
@@ -105,10 +110,10 @@ module XMLSecurity
|
|
105
110
|
cert = OpenSSL::X509::Certificate.new(cert_text)
|
106
111
|
|
107
112
|
# signature method
|
108
|
-
|
113
|
+
signature_algorithm = algorithm(REXML::XPath.first(signed_info_element, "//ds:SignatureMethod", {"ds"=>DSIG}))
|
109
114
|
|
110
|
-
|
111
|
-
return soft ? false : (raise ValidationError.new("Key validation error"))
|
115
|
+
unless cert.public_key.verify(signature_algorithm.new, signature, canon_string)
|
116
|
+
return soft ? false : (raise Onelogin::Saml::ValidationError.new("Key validation error"))
|
112
117
|
end
|
113
118
|
|
114
119
|
return true
|
@@ -125,17 +130,19 @@ module XMLSecurity
|
|
125
130
|
self.signed_element_id = reference_element.attribute("URI").value[1..-1] unless reference_element.nil?
|
126
131
|
end
|
127
132
|
|
128
|
-
def
|
129
|
-
algorithm = element.attribute(
|
130
|
-
|
133
|
+
def canon_algorithm(element)
|
134
|
+
algorithm = element.attribute('Algorithm').value if element
|
135
|
+
case algorithm
|
136
|
+
when "http://www.w3.org/2001/10/xml-exc-c14n#" then Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
|
137
|
+
when "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" then Nokogiri::XML::XML_C14N_1_0
|
138
|
+
when "http://www.w3.org/2006/12/xml-c14n11" then Nokogiri::XML::XML_C14N_1_1
|
139
|
+
else Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0
|
140
|
+
end
|
131
141
|
end
|
132
142
|
|
133
|
-
def
|
143
|
+
def algorithm(element)
|
134
144
|
algorithm = element.attribute("Algorithm").value if element
|
135
|
-
|
136
|
-
algorithm =~ /sha(.*?)$/i
|
137
|
-
algorithm = $1.to_i
|
138
|
-
end
|
145
|
+
algorithm = algorithm && algorithm =~ /sha(.*?)$/i && $1.to_i
|
139
146
|
case algorithm
|
140
147
|
when 256 then OpenSSL::Digest::SHA256
|
141
148
|
when 384 then OpenSSL::Digest::SHA384
|
@@ -145,5 +152,14 @@ module XMLSecurity
|
|
145
152
|
end
|
146
153
|
end
|
147
154
|
|
155
|
+
def extract_inclusive_namespaces
|
156
|
+
if element = REXML::XPath.first(self, "//ec:InclusiveNamespaces", { "ec" => C14N })
|
157
|
+
prefix_list = element.attributes.get_attribute("PrefixList").value
|
158
|
+
prefix_list.split(" ")
|
159
|
+
else
|
160
|
+
[]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
148
164
|
end
|
149
165
|
end
|
data/ruby-saml.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.email = %q{support@onelogin.com}
|
13
13
|
s.extra_rdoc_files = [
|
14
14
|
"LICENSE",
|
15
|
-
"README.
|
15
|
+
"README.md"
|
16
16
|
]
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.homepage = %q{http://github.com/onelogin/ruby-saml}
|
@@ -23,29 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.summary = %q{SAML Ruby Tookit}
|
24
24
|
s.test_files = `git ls-files test/*`.split("\n")
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
31
|
-
s.add_runtime_dependency(%q<canonix>, ["~> 0.1"])
|
32
|
-
s.add_runtime_dependency(%q<uuid>, ["~> 2.3"])
|
33
|
-
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
34
|
-
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
35
|
-
s.add_development_dependency(%q<mocha>, [">= 0"])
|
36
|
-
else
|
37
|
-
s.add_dependency(%q<canonix>, ["~> 0.1"])
|
38
|
-
s.add_dependency(%q<uuid>, ["~> 2.3"])
|
39
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
40
|
-
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
41
|
-
s.add_dependency(%q<mocha>, [">= 0"])
|
42
|
-
end
|
43
|
-
else
|
44
|
-
s.add_dependency(%q<canonix>, ["~> 0.1"])
|
45
|
-
s.add_dependency(%q<uuid>, ["~> 2.3"])
|
46
|
-
s.add_dependency(%q<shoulda>, [">= 0"])
|
47
|
-
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
48
|
-
s.add_dependency(%q<mocha>, [">= 0"])
|
49
|
-
end
|
26
|
+
s.add_runtime_dependency("canonix", ["0.1.1"])
|
27
|
+
s.add_runtime_dependency("uuid", ["~> 2.3"])
|
28
|
+
s.add_runtime_dependency("nokogiri")
|
50
29
|
end
|
51
|
-
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
+
|
3
|
+
class RequestTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "Logoutrequest" do
|
6
|
+
settings = Onelogin::Saml::Settings.new
|
7
|
+
|
8
|
+
should "create the deflated SAMLRequest URL parameter" do
|
9
|
+
settings.idp_slo_target_url = "http://unauth.com/logout"
|
10
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings)
|
11
|
+
assert unauth_url =~ /^http:\/\/unauth\.com\/logout\?SAMLRequest=/
|
12
|
+
|
13
|
+
inflated = decode_saml_request_payload(unauth_url)
|
14
|
+
|
15
|
+
assert_match /^<samlp:LogoutRequest/, inflated
|
16
|
+
end
|
17
|
+
|
18
|
+
should "support additional params" do
|
19
|
+
|
20
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings, { :hello => nil })
|
21
|
+
assert unauth_url =~ /&hello=$/
|
22
|
+
|
23
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings, { :foo => "bar" })
|
24
|
+
assert unauth_url =~ /&foo=bar$/
|
25
|
+
end
|
26
|
+
|
27
|
+
should "set sessionindex" do
|
28
|
+
settings.idp_slo_target_url = "http://example.com"
|
29
|
+
sessionidx = UUID.new.generate
|
30
|
+
settings.sessionindex = sessionidx
|
31
|
+
|
32
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings, { :name_id => "there" })
|
33
|
+
inflated = decode_saml_request_payload(unauth_url)
|
34
|
+
|
35
|
+
assert_match /<samlp:SessionIndex/, inflated
|
36
|
+
assert_match %r(#{sessionidx}</samlp:SessionIndex>), inflated
|
37
|
+
end
|
38
|
+
|
39
|
+
should "set name_identifier_value" do
|
40
|
+
settings = Onelogin::Saml::Settings.new
|
41
|
+
settings.idp_slo_target_url = "http://example.com"
|
42
|
+
settings.name_identifier_format = "transient"
|
43
|
+
name_identifier_value = "abc123"
|
44
|
+
settings.name_identifier_value = name_identifier_value
|
45
|
+
|
46
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings, { :name_id => "there" })
|
47
|
+
inflated = decode_saml_request_payload(unauth_url)
|
48
|
+
|
49
|
+
assert_match /<saml:NameID/, inflated
|
50
|
+
assert_match %r(#{name_identifier_value}</saml:NameID>), inflated
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when the target url doesn't contain a query string" do
|
54
|
+
should "create the SAMLRequest parameter correctly" do
|
55
|
+
settings = Onelogin::Saml::Settings.new
|
56
|
+
settings.idp_slo_target_url = "http://example.com"
|
57
|
+
|
58
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings)
|
59
|
+
assert unauth_url =~ /^http:\/\/example.com\?SAMLRequest/
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when the target url contains a query string" do
|
64
|
+
should "create the SAMLRequest parameter correctly" do
|
65
|
+
settings = Onelogin::Saml::Settings.new
|
66
|
+
settings.idp_slo_target_url = "http://example.com?field=value"
|
67
|
+
|
68
|
+
unauth_url = Onelogin::Saml::Logoutrequest.new.create(settings)
|
69
|
+
assert unauth_url =~ /^http:\/\/example.com\?field=value&SAMLRequest/
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "consumation of logout may need to track the transaction" do
|
74
|
+
should "have access to the request uuid" do
|
75
|
+
settings = Onelogin::Saml::Settings.new
|
76
|
+
settings.idp_slo_target_url = "http://example.com?field=value"
|
77
|
+
|
78
|
+
unauth_req = Onelogin::Saml::Logoutrequest.new
|
79
|
+
unauth_url = unauth_req.create(settings)
|
80
|
+
|
81
|
+
inflated = decode_saml_request_payload(unauth_url)
|
82
|
+
assert_match %r[ID='#{unauth_req.uuid}'], inflated
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def decode_saml_request_payload(unauth_url)
|
88
|
+
payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
|
89
|
+
decoded = Base64.decode64(payload)
|
90
|
+
|
91
|
+
zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
92
|
+
inflated = zstream.inflate(decoded)
|
93
|
+
zstream.finish
|
94
|
+
zstream.close
|
95
|
+
inflated
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
data/test/response_test.rb
CHANGED
@@ -27,6 +27,12 @@ class RubySamlTest < Test::Unit::TestCase
|
|
27
27
|
assert !response.name_id.nil?
|
28
28
|
end
|
29
29
|
|
30
|
+
should "default to raw input when a response is not Base64 encoded" do
|
31
|
+
decoded = Base64.decode64(response_document_2)
|
32
|
+
response = Onelogin::Saml::Response.new(decoded)
|
33
|
+
assert response.document
|
34
|
+
end
|
35
|
+
|
30
36
|
context "Assertion" do
|
31
37
|
should "only retreive an assertion with an ID that matches the signature's reference URI" do
|
32
38
|
response = Onelogin::Saml::Response.new(wrapped_response_2)
|
@@ -89,14 +95,34 @@ class RubySamlTest < Test::Unit::TestCase
|
|
89
95
|
assert response.name_id == "test@onelogin.com"
|
90
96
|
end
|
91
97
|
|
98
|
+
should "support dynamic namespace resolution on signature elements" do
|
99
|
+
response = Onelogin::Saml::Response.new(fixture("no_signature_ns.xml"))
|
100
|
+
response.stubs(:conditions).returns(nil)
|
101
|
+
settings = Onelogin::Saml::Settings.new
|
102
|
+
response.settings = settings
|
103
|
+
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
104
|
+
XMLSecurity::SignedDocument.any_instance.expects(:validate_doc).returns(true)
|
105
|
+
assert response.validate!
|
106
|
+
end
|
107
|
+
|
92
108
|
should "validate ADFS assertions" do
|
93
|
-
response = Onelogin::Saml::Response.new(fixture(:
|
109
|
+
response = Onelogin::Saml::Response.new(fixture(:adfs_response_sha256))
|
94
110
|
response.stubs(:conditions).returns(nil)
|
95
111
|
settings = Onelogin::Saml::Settings.new
|
96
112
|
settings.idp_cert_fingerprint = "28:74:9B:E8:1F:E8:10:9C:A8:7C:A9:C3:E3:C5:01:6C:92:1C:B4:BA"
|
97
113
|
response.settings = settings
|
98
114
|
assert response.validate!
|
99
115
|
end
|
116
|
+
|
117
|
+
should "validate SAML 2.0 XML structure" do
|
118
|
+
resp_xml = Base64.decode64(response_document_4).gsub(/emailAddress/,'test')
|
119
|
+
response = Onelogin::Saml::Response.new(Base64.encode64(resp_xml))
|
120
|
+
response.stubs(:conditions).returns(nil)
|
121
|
+
settings = Onelogin::Saml::Settings.new
|
122
|
+
settings.idp_cert_fingerprint = signature_fingerprint_1
|
123
|
+
response.settings = settings
|
124
|
+
assert_raises(Onelogin::Saml::ValidationError, 'Digest mismatch'){ response.validate! }
|
125
|
+
end
|
100
126
|
end
|
101
127
|
|
102
128
|
context "#name_id" do
|
@@ -171,11 +197,23 @@ class RubySamlTest < Test::Unit::TestCase
|
|
171
197
|
end
|
172
198
|
|
173
199
|
context "#issuer" do
|
174
|
-
should "return the issuer
|
200
|
+
should "return the issuer inside the response assertion" do
|
201
|
+
response = Onelogin::Saml::Response.new(response_document)
|
202
|
+
assert_equal "https://app.onelogin.com/saml/metadata/13590", response.issuer
|
203
|
+
end
|
204
|
+
|
205
|
+
should "return the issuer inside the response" do
|
175
206
|
response = Onelogin::Saml::Response.new(response_document_2)
|
176
207
|
assert_equal "wibble", response.issuer
|
177
208
|
end
|
178
209
|
end
|
210
|
+
|
211
|
+
context "#success" do
|
212
|
+
should "find a status code that says success" do
|
213
|
+
response = Onelogin::Saml::Response.new(response_document)
|
214
|
+
response.success?
|
215
|
+
end
|
216
|
+
end
|
179
217
|
|
180
218
|
end
|
181
219
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_0263a07b-205f-479c-90fc-7495715ecbbf" Version="2.0" IssueInstant="2011-06-22T12:49:30.348Z" Destination="https://someone.example.com/endpoint" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_fc4a34b0-7efb-012e-caae-782bcb13bb38">
|
3
|
+
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://login.example.com/issuer</Issuer>
|
4
|
+
<samlp:Status>
|
5
|
+
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
|
6
|
+
</samlp:Status>
|
7
|
+
<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_721b4a5a-d7e1-4861-9754-a9b197b6f9ab" IssueInstant="2011-06-22T12:49:30.348Z" Version="2.0">
|
8
|
+
<Issuer>http://login.example.com/issuer</Issuer>
|
9
|
+
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
10
|
+
<ds:SignedInfo>
|
11
|
+
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
12
|
+
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha1"/>
|
13
|
+
<ds:Reference URI="#_721b4a5a-d7e1-4861-9754-a9b197b6f9ab">
|
14
|
+
<ds:Transforms>
|
15
|
+
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
16
|
+
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
17
|
+
</ds:Transforms>
|
18
|
+
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha1"/>
|
19
|
+
<ds:DigestValue>tGpkynNC34A5SFqDSfXmPSiIGpU=</ds:DigestValue>
|
20
|
+
</ds:Reference>
|
21
|
+
</ds:SignedInfo>
|
22
|
+
<ds:SignatureValue>WXtmslqh2npLtwhvU8yVx0pvH7E1s8ASksv7VtWirQDFrRRO9k+sNnQcGzA75QNyd6nP+T2e+ofIWyj8G70Rd6gEU4ZmV1vlGVq49Ilc7r/oxauitIuasOvrmpyHCXRbttYeWz4T5xoTCDx9RZQvI4fdrFugrymFT2OREFx1lSk=</ds:SignatureValue>
|
23
|
+
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
|
24
|
+
<ds:X509Data>
|
25
|
+
<ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxekNDQXhTZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBRENCaGpFTE1Ba0dBMVVFQmhNQ1FWVXgKRERBS0JnTlZCQWdUQTA1VFZ6RVBNQTBHQTFVRUJ4TUdVM2xrYm1WNU1Rd3dDZ1lEVlFRS0RBTlFTVlF4Q1RBSApCZ05WQkFzTUFERVlNQllHQTFVRUF3d1BiR0YzY21WdVkyVndhWFF1WTI5dE1TVXdJd1lKS29aSWh2Y05BUWtCCkRCWnNZWGR5Wlc1alpTNXdhWFJBWjIxaGFXd3VZMjl0TUI0WERURXlNRFF4T1RJeU5UUXhPRm9YRFRNeU1EUXgKTkRJeU5UUXhPRm93Z1lZeEN6QUpCZ05WQkFZVEFrRlZNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVApCbE41Wkc1bGVURU1NQW9HQTFVRUNnd0RVRWxVTVFrd0J3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psCmJtTmxjR2wwTG1OdmJURWxNQ01HQ1NxR1NJYjNEUUVKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnYKYlRDQm56QU5CZ2txaGtpRzl3MEJBUUVGQUFPQmpRQXdnWWtDZ1lFQXFqaWUzUjJvaStwRGFldndJeXMvbWJVVApubkdsa3h0ZGlrcnExMXZleHd4SmlQTmhtaHFSVzNtVXVKRXpsbElkVkw2RW14R1lUcXBxZjkzSGxoa3NhZUowCjhVZ2pQOVVtTVlyaFZKdTFqY0ZXVjdmei9yKzIxL2F3VG5EVjlzTVlRcXVJUllZeTdiRzByMU9iaXdkb3ZudGsKN2dGSTA2WjB2WmFjREU1Ym9xVUNBd0VBQWFPQ0FTVXdnZ0VoTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRRApBZ1VnTUIwR0ExVWREZ1FXQkJTUk9OOEdKOG8rOGpnRnRqa3R3WmRxeDZCUnlUQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQVRBZEJnbGdoa2dCaHZoQ0FRMEVFQllPVkdWemRDQllOVEE1SUdObGNuUXdnYk1HQTFVZEl3U0IKcXpDQnFJQVVrVGpmQmlmS1B2STRCYlk1TGNHWGFzZWdVY21oZ1l5a2dZa3dnWVl4Q3pBSkJnTlZCQVlUQWtGVgpNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVEJsTjVaRzVsZVRFTU1Bb0dBMVVFQ2d3RFVFbFVNUWt3CkJ3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psYm1ObGNHbDBMbU52YlRFbE1DTUdDU3FHU0liM0RRRUoKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnZiWUlCQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9CZ1FDRQpUQWVKVERTQVc2ejFVRlRWN1FyZWg0VUxGT1JhajkrZUN1RjNLV0RIYyswSVFDajlyZG5ERzRRL3dmNy9yYVEwCkpuUFFDU0NkclBMSmV5b1BIN1FhVHdvYUY3ZHpWdzRMQ3N5TkpURld4NGNNNTBWdzZSNWZET2dpQzhic2ZmUzgKQkptb3VscnJaRE5OVmpHOG1XNmNMeHJZdlZRT3JSVmVjQ0ZJZ3NzQ2JBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=</ds:X509Certificate>
|
26
|
+
</ds:X509Data>
|
27
|
+
</KeyInfo>
|
28
|
+
</ds:Signature>
|
29
|
+
<Subject>
|
30
|
+
<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">hello@example.com</NameID>
|
31
|
+
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
32
|
+
<SubjectConfirmationData InResponseTo="_fc4a34b0-7efb-012e-caae-782bcb13bb38" NotOnOrAfter="2011-06-22T12:54:30.348Z" Recipient="https://someone.example.com/endpoint"/>
|
33
|
+
</SubjectConfirmation>
|
34
|
+
</Subject>
|
35
|
+
<Conditions NotBefore="2011-06-22T12:49:30.332Z" NotOnOrAfter="2011-06-22T13:49:30.332Z">
|
36
|
+
<AudienceRestriction>
|
37
|
+
<Audience>example.com</Audience>
|
38
|
+
</AudienceRestriction>
|
39
|
+
</Conditions>
|
40
|
+
<AuthnStatement AuthnInstant="2011-06-22T12:49:30.112Z" SessionIndex="_721b4a5a-d7e1-4861-9754-a9b197b6f9ab">
|
41
|
+
<AuthnContext>
|
42
|
+
<AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
|
43
|
+
</AuthnContext>
|
44
|
+
</AuthnStatement>
|
45
|
+
</Assertion>
|
46
|
+
</samlp:Response>
|
File without changes
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_0263a07b-205f-479c-90fc-7495715ecbbf" Version="2.0" IssueInstant="2011-06-22T12:49:30.348Z" Destination="https://someone.example.com/endpoint" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" InResponseTo="_fc4a34b0-7efb-012e-caae-782bcb13bb38">
|
3
|
+
<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://login.example.com/issuer</Issuer>
|
4
|
+
<samlp:Status>
|
5
|
+
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
|
6
|
+
</samlp:Status>
|
7
|
+
<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="_721b4a5a-d7e1-4861-9754-a9b197b6f9ab" IssueInstant="2011-06-22T12:49:30.348Z" Version="2.0">
|
8
|
+
<Issuer>http://login.example.com/issuer</Issuer>
|
9
|
+
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
10
|
+
<ds:SignedInfo>
|
11
|
+
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
12
|
+
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"/>
|
13
|
+
<ds:Reference URI="#_721b4a5a-d7e1-4861-9754-a9b197b6f9ab">
|
14
|
+
<ds:Transforms>
|
15
|
+
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
16
|
+
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
17
|
+
</ds:Transforms>
|
18
|
+
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha384"/>
|
19
|
+
<ds:DigestValue>XU0mb78TVA+VwcA71jxe5osjiOzOP/OwDcJ8t/mn2d9+/V2zxejEo9+fkSY2ZR0Z</ds:DigestValue>
|
20
|
+
</ds:Reference>
|
21
|
+
</ds:SignedInfo>
|
22
|
+
<ds:SignatureValue>bq1zDllmAFzx0O3HAAoedSqQIl/n2+mK2Vx1pK0/yEpuc84ovwmau/ZfHk3MFNQjuxL+JmlO7I3c6CEmOGeAupFTpnFGkRfJGSu6ilvcL4yasPq80LNEcCYhApiEW2pJXs5t3sfOdG2MJHTuMvz4MtnrLd9Cuf/EQK2a27HDrB4=</ds:SignatureValue>
|
23
|
+
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
|
24
|
+
<ds:X509Data>
|
25
|
+
<ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxekNDQXhTZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBRENCaGpFTE1Ba0dBMVVFQmhNQ1FWVXgKRERBS0JnTlZCQWdUQTA1VFZ6RVBNQTBHQTFVRUJ4TUdVM2xrYm1WNU1Rd3dDZ1lEVlFRS0RBTlFTVlF4Q1RBSApCZ05WQkFzTUFERVlNQllHQTFVRUF3d1BiR0YzY21WdVkyVndhWFF1WTI5dE1TVXdJd1lKS29aSWh2Y05BUWtCCkRCWnNZWGR5Wlc1alpTNXdhWFJBWjIxaGFXd3VZMjl0TUI0WERURXlNRFF4T1RJeU5UUXhPRm9YRFRNeU1EUXgKTkRJeU5UUXhPRm93Z1lZeEN6QUpCZ05WQkFZVEFrRlZNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVApCbE41Wkc1bGVURU1NQW9HQTFVRUNnd0RVRWxVTVFrd0J3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psCmJtTmxjR2wwTG1OdmJURWxNQ01HQ1NxR1NJYjNEUUVKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnYKYlRDQm56QU5CZ2txaGtpRzl3MEJBUUVGQUFPQmpRQXdnWWtDZ1lFQXFqaWUzUjJvaStwRGFldndJeXMvbWJVVApubkdsa3h0ZGlrcnExMXZleHd4SmlQTmhtaHFSVzNtVXVKRXpsbElkVkw2RW14R1lUcXBxZjkzSGxoa3NhZUowCjhVZ2pQOVVtTVlyaFZKdTFqY0ZXVjdmei9yKzIxL2F3VG5EVjlzTVlRcXVJUllZeTdiRzByMU9iaXdkb3ZudGsKN2dGSTA2WjB2WmFjREU1Ym9xVUNBd0VBQWFPQ0FTVXdnZ0VoTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRRApBZ1VnTUIwR0ExVWREZ1FXQkJTUk9OOEdKOG8rOGpnRnRqa3R3WmRxeDZCUnlUQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQVRBZEJnbGdoa2dCaHZoQ0FRMEVFQllPVkdWemRDQllOVEE1SUdObGNuUXdnYk1HQTFVZEl3U0IKcXpDQnFJQVVrVGpmQmlmS1B2STRCYlk1TGNHWGFzZWdVY21oZ1l5a2dZa3dnWVl4Q3pBSkJnTlZCQVlUQWtGVgpNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVEJsTjVaRzVsZVRFTU1Bb0dBMVVFQ2d3RFVFbFVNUWt3CkJ3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psYm1ObGNHbDBMbU52YlRFbE1DTUdDU3FHU0liM0RRRUoKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnZiWUlCQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9CZ1FDRQpUQWVKVERTQVc2ejFVRlRWN1FyZWg0VUxGT1JhajkrZUN1RjNLV0RIYyswSVFDajlyZG5ERzRRL3dmNy9yYVEwCkpuUFFDU0NkclBMSmV5b1BIN1FhVHdvYUY3ZHpWdzRMQ3N5TkpURld4NGNNNTBWdzZSNWZET2dpQzhic2ZmUzgKQkptb3VscnJaRE5OVmpHOG1XNmNMeHJZdlZRT3JSVmVjQ0ZJZ3NzQ2JBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=</ds:X509Certificate>
|
26
|
+
</ds:X509Data>
|
27
|
+
</KeyInfo>
|
28
|
+
</ds:Signature>
|
29
|
+
<Subject>
|
30
|
+
<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">hello@example.com</NameID>
|
31
|
+
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
32
|
+
<SubjectConfirmationData InResponseTo="_fc4a34b0-7efb-012e-caae-782bcb13bb38" NotOnOrAfter="2011-06-22T12:54:30.348Z" Recipient="https://someone.example.com/endpoint"/>
|
33
|
+
</SubjectConfirmation>
|
34
|
+
</Subject>
|
35
|
+
<Conditions NotBefore="2011-06-22T12:49:30.332Z" NotOnOrAfter="2011-06-22T13:49:30.332Z">
|
36
|
+
<AudienceRestriction>
|
37
|
+
<Audience>example.com</Audience>
|
38
|
+
</AudienceRestriction>
|
39
|
+
</Conditions>
|
40
|
+
<AuthnStatement AuthnInstant="2011-06-22T12:49:30.112Z" SessionIndex="_721b4a5a-d7e1-4861-9754-a9b197b6f9ab">
|
41
|
+
<AuthnContext>
|
42
|
+
<AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthnContextClassRef>
|
43
|
+
</AuthnContext>
|
44
|
+
</AuthnStatement>
|
45
|
+
</Assertion>
|
46
|
+
</samlp:Response>
|