ruby-saml 0.8.8 → 0.8.13
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.
Potentially problematic release.
This version of ruby-saml might be problematic. Click here for more details.
- checksums.yaml +7 -7
- data/Gemfile +11 -1
- data/README.md +5 -2
- data/Rakefile +0 -14
- data/lib/onelogin/ruby-saml/authrequest.rb +86 -20
- data/lib/onelogin/ruby-saml/logoutrequest.rb +95 -20
- data/lib/onelogin/ruby-saml/logoutresponse.rb +5 -28
- data/lib/onelogin/ruby-saml/metadata.rb +5 -5
- data/lib/onelogin/ruby-saml/response.rb +187 -4
- data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
- data/lib/onelogin/ruby-saml/settings.rb +146 -10
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +158 -0
- data/lib/onelogin/ruby-saml/utils.rb +169 -0
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +2 -1
- data/lib/xml_security.rb +330 -78
- data/test/certificates/ruby-saml-2.crt +15 -0
- data/test/certificates/ruby-saml.crt +14 -0
- data/test/certificates/ruby-saml.key +15 -0
- data/test/logoutrequest_test.rb +177 -44
- data/test/logoutresponse_test.rb +25 -29
- data/test/request_test.rb +100 -37
- data/test/response_test.rb +213 -111
- data/test/responses/adfs_response_xmlns.xml +45 -0
- data/test/responses/encrypted_new_attack.xml.base64 +1 -0
- data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
- data/test/responses/invalids/no_signature.xml.base64 +1 -0
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
- data/test/responses/logoutresponse_fixtures.rb +6 -6
- data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
- data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
- data/test/responses/response_with_signed_assertion_3.xml +30 -0
- data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
- data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
- data/test/responses/response_wrapped.xml.base64 +150 -0
- data/test/responses/valid_response.xml.base64 +1 -0
- data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
- data/test/settings_test.rb +7 -7
- data/test/slo_logoutresponse_test.rb +226 -0
- data/test/test_helper.rb +117 -12
- data/test/utils_test.rb +10 -10
- data/test/xml_security_test.rb +310 -68
- metadata +88 -45
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICVDCCAb2gAwIBAgIBADANBgkqhkiG9w0BAQ0FADBHMQswCQYDVQQGEwJ1czEQ
|
3
|
+
MA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIGA1UEAwwLZXhh
|
4
|
+
bXBsZS5jb20wHhcNMTcwNDA3MDgzMDAzWhcNMjcwNDA1MDgzMDAzWjBHMQswCQYD
|
5
|
+
VQQGEwJ1czEQMA4GA1UECAwHZXhhbXBsZTEQMA4GA1UECgwHZXhhbXBsZTEUMBIG
|
6
|
+
A1UEAwwLZXhhbXBsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKhP
|
7
|
+
S4/0azxbQekHHewQGKD7Pivr3CDpsrKxY3xlVanxj427OwzOb5KUVzsDEazumt6s
|
8
|
+
ZFY8HfidsjXY4EYA4ZzyL7ciIAR5vlAsIYN9nJ4AwVDnN/RjVwj+TN6BqWPLpVIp
|
9
|
+
Hc6Dl005HyE0zJnk1DZDn2tQVrIzbD3FhCp7YeotAgMBAAGjUDBOMB0GA1UdDgQW
|
10
|
+
BBRYZx4thASfNvR/E7NsCF2IaZ7wIDAfBgNVHSMEGDAWgBRYZx4thASfNvR/E7Ns
|
11
|
+
CF2IaZ7wIDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBACz4aobx9aG3
|
12
|
+
kh+rNyrlgM3K6dYfnKG1/YH5sJCAOvg8kDr0fQAQifH8lFVWumKUMoAe0bFTfwWt
|
13
|
+
p/VJ8MprrEJth6PFeZdczpuv+fpLcNj2VmNVJqvQYvS4m36OnBFh1QFZW8UrbFIf
|
14
|
+
dtm2nuZ+twSKqfKwjLdqcoX0p39h7Uw/
|
15
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,14 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIICGzCCAYQCCQCNNcQXom32VDANBgkqhkiG9w0BAQUFADBSMQswCQYDVQQGEwJV
|
3
|
+
UzELMAkGA1UECBMCSU4xFTATBgNVBAcTDEluZGlhbmFwb2xpczERMA8GA1UEChMI
|
4
|
+
T25lTG9naW4xDDAKBgNVBAsTA0VuZzAeFw0xNDA0MjMxODQxMDFaFw0xNTA0MjMx
|
5
|
+
ODQxMDFaMFIxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTjEVMBMGA1UEBxMMSW5k
|
6
|
+
aWFuYXBvbGlzMREwDwYDVQQKEwhPbmVMb2dpbjEMMAoGA1UECxMDRW5nMIGfMA0G
|
7
|
+
CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo6m+QZvYQ/xL0ElLgupK1QDcYL4f5Pckw
|
8
|
+
sNgS9pUvV7fzTqCHk8ThLxTk42MQ2McJsOeUJVP728KhymjFCqxgP4VuwRk9rpAl
|
9
|
+
0+mhy6MPdyjyA6G14jrDWS65ysLchK4t/vwpEDz0SQlEoG1kMzllSm7zZS3XregA
|
10
|
+
7DjNaUYQqwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBALM2vGCiQ/vm+a6v40+VX2zd
|
11
|
+
qHA2Q/1vF1ibQzJ54MJCOVWvs+vQXfZFhdm0OPM2IrDU7oqvKPqP6xOAeJK6H0yP
|
12
|
+
7M4YL3fatSvIYmmfyXC9kt3Svz/NyrHzPhUnJ0ye/sUSXxnzQxwcm/9PwAqrQaA3
|
13
|
+
QpQkH57ybF/OoryPe+2h
|
14
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,15 @@
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
2
|
+
MIICXAIBAAKBgQDo6m+QZvYQ/xL0ElLgupK1QDcYL4f5PckwsNgS9pUvV7fzTqCH
|
3
|
+
k8ThLxTk42MQ2McJsOeUJVP728KhymjFCqxgP4VuwRk9rpAl0+mhy6MPdyjyA6G1
|
4
|
+
4jrDWS65ysLchK4t/vwpEDz0SQlEoG1kMzllSm7zZS3XregA7DjNaUYQqwIDAQAB
|
5
|
+
AoGBALGR6bRBit+yV5TUU3MZSrf8WQSLWDLgs/33FQSAEYSib4+DJke2lKbI6jkG
|
6
|
+
UoSJgFUXFbaQLtMY2+3VDsMKPBdAge9gIdvbkC4yoKjLGm/FBDOxxZcfLpR+9OPq
|
7
|
+
U3qM9D0CNuliBWI7Je+p/zs09HIYucpDXy9E18KA1KNF6rfhAkEA9KoNam6wAKnm
|
8
|
+
vMzz31ws3RuIOUeo2rx6aaVY95+P9tTxd6U+pNkwxy1aCGP+InVSwlYNA1aQ4Axi
|
9
|
+
/GdMIWMkxwJBAPO1CP7cQNZQmu7yusY+GUObDII5YK9WLaY4RAicn5378crPBFxv
|
10
|
+
Ukqf9G6FHo7u88iTCIp+vwa3Hn9Tumg3iP0CQQDgUXWBasCVqzCxU5wY4tMDWjXY
|
11
|
+
hpoLCpmVeRML3dDJt004rFm2HKe7Rhpw7PTZNQZOxUSjFeA4e0LaNf838UWLAkB8
|
12
|
+
QfbHM3ffjhOg96PhhjINdVWoZCb230LBOHj/xxPfUmFTHcBEfQIBSJMxcrBFAnLL
|
13
|
+
9qPpMXymqOFk3ETz9DTlAj8E0qGbp78aVbTOtuwEwNJII+RPw+Zkc+lKR+yaWkAz
|
14
|
+
fIXw527NPHH3+rnBG72wyZr9ud4LAum9jh+5No1LQpk=
|
15
|
+
-----END RSA PRIVATE KEY-----
|
data/test/logoutrequest_test.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
2
|
|
3
|
-
class
|
3
|
+
class LogoutRequestTest < Minitest::Test
|
4
4
|
|
5
|
-
|
6
|
-
settings
|
5
|
+
describe "Logoutrequest" do
|
6
|
+
let(:settings) { OneLogin::RubySaml::Settings.new }
|
7
7
|
|
8
|
-
|
8
|
+
before do
|
9
9
|
settings.idp_slo_target_url = "http://unauth.com/logout"
|
10
10
|
settings.name_identifier_value = "f00f00"
|
11
|
+
end
|
11
12
|
|
13
|
+
it "create the deflated SAMLRequest URL parameter" do
|
12
14
|
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
|
13
15
|
assert unauth_url =~ /^http:\/\/unauth\.com\/logout\?SAMLRequest=/
|
14
16
|
|
@@ -17,8 +19,7 @@ class RequestTest < Test::Unit::TestCase
|
|
17
19
|
assert_match /^<samlp:LogoutRequest/, inflated
|
18
20
|
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
+
it "support additional params" do
|
22
23
|
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :hello => nil })
|
23
24
|
assert unauth_url =~ /&hello=$/
|
24
25
|
|
@@ -26,9 +27,8 @@ class RequestTest < Test::Unit::TestCase
|
|
26
27
|
assert unauth_url =~ /&foo=bar$/
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
sessionidx = UUID.new.generate
|
30
|
+
it "set sessionindex" do
|
31
|
+
sessionidx = random_id
|
32
32
|
settings.sessionindex = sessionidx
|
33
33
|
|
34
34
|
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :name_id => "there" })
|
@@ -38,9 +38,7 @@ class RequestTest < Test::Unit::TestCase
|
|
38
38
|
assert_match %r(#{sessionidx}</samlp:SessionIndex>), inflated
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
settings = OneLogin::RubySaml::Settings.new
|
43
|
-
settings.idp_slo_target_url = "http://example.com"
|
41
|
+
it "set name_identifier_value" do
|
44
42
|
settings.name_identifier_format = "transient"
|
45
43
|
name_identifier_value = "abc123"
|
46
44
|
settings.name_identifier_value = name_identifier_value
|
@@ -52,41 +50,25 @@ class RequestTest < Test::Unit::TestCase
|
|
52
50
|
assert_match %r(#{name_identifier_value}</saml:NameID>), inflated
|
53
51
|
end
|
54
52
|
|
55
|
-
|
56
|
-
|
57
|
-
settings.idp_slo_target_url = "http://example.com"
|
58
|
-
settings.name_identifier_format = nil
|
59
|
-
|
60
|
-
assert_raises(OneLogin::RubySaml::ValidationError) { OneLogin::RubySaml::Logoutrequest.new.create(settings) }
|
61
|
-
end
|
62
|
-
|
63
|
-
context "when the target url doesn't contain a query string" do
|
64
|
-
should "create the SAMLRequest parameter correctly" do
|
65
|
-
settings = OneLogin::RubySaml::Settings.new
|
53
|
+
describe "when the target url doesn't contain a query string" do
|
54
|
+
it "create the SAMLRequest parameter correctly" do
|
66
55
|
settings.idp_slo_target_url = "http://example.com"
|
67
|
-
settings.name_identifier_value = "f00f00"
|
68
|
-
|
69
56
|
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
|
70
57
|
assert unauth_url =~ /^http:\/\/example.com\?SAMLRequest/
|
71
58
|
end
|
72
59
|
end
|
73
60
|
|
74
|
-
|
75
|
-
|
76
|
-
settings = OneLogin::RubySaml::Settings.new
|
61
|
+
describe "when the target url contains a query string" do
|
62
|
+
it "create the SAMLRequest parameter correctly" do
|
77
63
|
settings.idp_slo_target_url = "http://example.com?field=value"
|
78
|
-
settings.name_identifier_value = "f00f00"
|
79
|
-
|
80
64
|
unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
|
81
65
|
assert unauth_url =~ /^http:\/\/example.com\?field=value&SAMLRequest/
|
82
66
|
end
|
83
67
|
end
|
84
68
|
|
85
|
-
|
86
|
-
|
87
|
-
settings = OneLogin::RubySaml::Settings.new
|
69
|
+
describe "consumation of logout may need to track the transaction" do
|
70
|
+
it "have access to the request uuid" do
|
88
71
|
settings.idp_slo_target_url = "http://example.com?field=value"
|
89
|
-
settings.name_identifier_value = "f00f00"
|
90
72
|
|
91
73
|
unauth_req = OneLogin::RubySaml::Logoutrequest.new
|
92
74
|
unauth_url = unauth_req.create(settings)
|
@@ -95,17 +77,168 @@ class RequestTest < Test::Unit::TestCase
|
|
95
77
|
assert_match %r[ID='#{unauth_req.uuid}'], inflated
|
96
78
|
end
|
97
79
|
end
|
98
|
-
end
|
99
80
|
|
100
|
-
def decode_saml_request_payload(unauth_url)
|
101
|
-
payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
|
102
|
-
decoded = Base64.decode64(payload)
|
103
81
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
82
|
+
describe "when the settings indicate to sign (embedded) logout request" do
|
83
|
+
|
84
|
+
before do
|
85
|
+
# sign the logout request
|
86
|
+
settings.security[:logout_requests_signed] = true
|
87
|
+
settings.security[:embed_sign] = true
|
88
|
+
settings.certificate = ruby_saml_cert_text
|
89
|
+
settings.private_key = ruby_saml_key_text
|
90
|
+
end
|
91
|
+
|
92
|
+
it "doesn't sign through create_xml_document" do
|
93
|
+
unauth_req = OneLogin::RubySaml::Logoutrequest.new
|
94
|
+
inflated = unauth_req.create_xml_document(settings).to_s
|
95
|
+
|
96
|
+
refute_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
|
97
|
+
refute_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
|
98
|
+
refute_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
|
99
|
+
end
|
100
|
+
|
101
|
+
it "sign unsigned request" do
|
102
|
+
unauth_req = OneLogin::RubySaml::Logoutrequest.new
|
103
|
+
unauth_req_doc = unauth_req.create_xml_document(settings)
|
104
|
+
inflated = unauth_req_doc.to_s
|
105
|
+
|
106
|
+
refute_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
|
107
|
+
refute_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
|
108
|
+
refute_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
|
109
|
+
|
110
|
+
inflated = unauth_req.sign_document(unauth_req_doc, settings).to_s
|
111
|
+
|
112
|
+
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
|
113
|
+
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
|
114
|
+
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
|
115
|
+
end
|
116
|
+
|
117
|
+
it "signs through create_logout_request_xml_doc" do
|
118
|
+
unauth_req = OneLogin::RubySaml::Logoutrequest.new
|
119
|
+
inflated = unauth_req.create_logout_request_xml_doc(settings).to_s
|
120
|
+
|
121
|
+
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
|
122
|
+
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
|
123
|
+
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
|
124
|
+
end
|
125
|
+
|
126
|
+
it "created a signed logout request" do
|
127
|
+
settings.compress_request = true
|
128
|
+
|
129
|
+
unauth_req = OneLogin::RubySaml::Logoutrequest.new
|
130
|
+
unauth_url = unauth_req.create(settings)
|
131
|
+
|
132
|
+
inflated = decode_saml_request_payload(unauth_url)
|
133
|
+
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
|
134
|
+
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
|
135
|
+
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
|
136
|
+
end
|
137
|
+
|
138
|
+
it "create a signed logout request with 256 digest and signature method" do
|
139
|
+
settings.compress_request = false
|
140
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
|
141
|
+
settings.security[:digest_method] = XMLSecurity::Document::SHA256
|
110
142
|
|
143
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
|
144
|
+
request_xml = Base64.decode64(params["SAMLRequest"])
|
145
|
+
|
146
|
+
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
|
147
|
+
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'/>], request_xml
|
148
|
+
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha256'/>], request_xml
|
149
|
+
end
|
150
|
+
|
151
|
+
it "create a signed logout request with 512 digest and signature method RSA_SHA384" do
|
152
|
+
settings.compress_request = false
|
153
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
|
154
|
+
settings.security[:digest_method] = XMLSecurity::Document::SHA512
|
155
|
+
|
156
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
|
157
|
+
request_xml = Base64.decode64(params["SAMLRequest"])
|
158
|
+
|
159
|
+
assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
|
160
|
+
assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'/>], request_xml
|
161
|
+
assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha512'/>], request_xml
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "#create_params when the settings indicate to sign the logout request" do
|
166
|
+
|
167
|
+
let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
|
168
|
+
|
169
|
+
before do
|
170
|
+
# sign the logout request
|
171
|
+
settings.security[:logout_requests_signed] = true
|
172
|
+
settings.security[:embed_sign] = false
|
173
|
+
settings.certificate = ruby_saml_cert_text
|
174
|
+
settings.private_key = ruby_saml_key_text
|
175
|
+
end
|
176
|
+
|
177
|
+
it "create a signature parameter with RSA_SHA1 / SHA1 and validate it" do
|
178
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
|
179
|
+
|
180
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
|
181
|
+
assert params['SAMLRequest']
|
182
|
+
assert params[:RelayState]
|
183
|
+
assert params['Signature']
|
184
|
+
assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
|
185
|
+
|
186
|
+
query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
|
187
|
+
query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
|
188
|
+
query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
189
|
+
|
190
|
+
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
191
|
+
assert_equal signature_algorithm, OpenSSL::Digest::SHA1
|
192
|
+
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
193
|
+
end
|
194
|
+
|
195
|
+
it "create a signature parameter with RSA_SHA256 / SHA256 and validate it" do
|
196
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
|
197
|
+
|
198
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
|
199
|
+
assert params['Signature']
|
200
|
+
assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
|
201
|
+
|
202
|
+
query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
|
203
|
+
query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
|
204
|
+
query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
205
|
+
|
206
|
+
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
207
|
+
assert_equal signature_algorithm, OpenSSL::Digest::SHA256
|
208
|
+
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "create a signature parameter with RSA_SHA384 / SHA384 and validate it" do
|
212
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
|
213
|
+
|
214
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
|
215
|
+
assert params['Signature']
|
216
|
+
assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA384
|
217
|
+
|
218
|
+
query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
|
219
|
+
query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
|
220
|
+
query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
221
|
+
|
222
|
+
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
223
|
+
assert_equal signature_algorithm, OpenSSL::Digest::SHA384
|
224
|
+
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "create a signature parameter with RSA_SHA512 / SHA512 and validate it" do
|
228
|
+
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA512
|
229
|
+
|
230
|
+
params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
|
231
|
+
assert params['Signature']
|
232
|
+
assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA512
|
233
|
+
|
234
|
+
query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
|
235
|
+
query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
|
236
|
+
query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
|
237
|
+
|
238
|
+
signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
|
239
|
+
assert_equal signature_algorithm, OpenSSL::Digest::SHA512
|
240
|
+
assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
111
244
|
end
|
data/test/logoutresponse_test.rb
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
-
require
|
3
|
-
require 'responses/logoutresponse_fixtures'
|
4
|
-
class RubySamlTest < Test::Unit::TestCase
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "responses/logoutresponse_fixtures"))
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
class LogoutResponseTest < Minitest::Test
|
5
|
+
|
6
|
+
describe "Logoutresponse" do
|
7
|
+
|
8
|
+
describe "#new" do
|
9
|
+
it "raise an exception when response is initialized with nil" do
|
9
10
|
assert_raises(ArgumentError) { OneLogin::RubySaml::Logoutresponse.new(nil) }
|
10
11
|
end
|
11
|
-
|
12
|
+
it "default to empty settings" do
|
12
13
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new( valid_response)
|
13
14
|
assert logoutresponse.settings.nil?
|
14
15
|
end
|
15
|
-
|
16
|
+
it "accept constructor-injected settings" do
|
16
17
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings)
|
17
18
|
assert !logoutresponse.settings.nil?
|
18
19
|
end
|
19
|
-
|
20
|
+
it "accept constructor-injected options" do
|
20
21
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, nil, { :foo => :bar} )
|
21
22
|
assert !logoutresponse.options.empty?
|
22
23
|
end
|
23
|
-
|
24
|
+
it "support base64 encoded responses" do
|
24
25
|
expected_response = valid_response
|
25
26
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(Base64.encode64(expected_response), settings)
|
26
27
|
|
@@ -28,21 +29,21 @@ class RubySamlTest < Test::Unit::TestCase
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
describe "#validate" do
|
33
|
+
it "validate the response" do
|
33
34
|
in_relation_to_request_id = random_id
|
34
35
|
|
35
36
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
|
36
37
|
|
37
38
|
assert logoutresponse.validate
|
38
39
|
|
39
|
-
assert_equal settings.
|
40
|
+
assert_equal settings.sp_entity_id, logoutresponse.issuer
|
40
41
|
assert_equal in_relation_to_request_id, logoutresponse.in_response_to
|
41
42
|
|
42
43
|
assert logoutresponse.success?
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
+
it "invalidate responses with wrong id when given option :matches_uuid" do
|
46
47
|
|
47
48
|
expected_request_id = "_some_other_expected_uuid"
|
48
49
|
opts = { :matches_request_id => expected_request_id}
|
@@ -50,10 +51,10 @@ class RubySamlTest < Test::Unit::TestCase
|
|
50
51
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response, settings, opts)
|
51
52
|
|
52
53
|
assert !logoutresponse.validate
|
53
|
-
|
54
|
+
assert expected_request_id != logoutresponse.in_response_to
|
54
55
|
end
|
55
56
|
|
56
|
-
|
57
|
+
it "invalidate responses with wrong request status" do
|
57
58
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
|
58
59
|
|
59
60
|
assert !logoutresponse.validate
|
@@ -61,8 +62,8 @@ class RubySamlTest < Test::Unit::TestCase
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
|
-
|
65
|
-
|
65
|
+
describe "#validate!" do
|
66
|
+
it "validates good responses" do
|
66
67
|
in_relation_to_request_id = random_id
|
67
68
|
|
68
69
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_response({:uuid => in_relation_to_request_id}), settings)
|
@@ -70,7 +71,7 @@ class RubySamlTest < Test::Unit::TestCase
|
|
70
71
|
logoutresponse.validate!
|
71
72
|
end
|
72
73
|
|
73
|
-
|
74
|
+
it "raises validation error when matching for wrong request id" do
|
74
75
|
|
75
76
|
expected_request_id = "_some_other_expected_id"
|
76
77
|
opts = { :matches_request_id => expected_request_id}
|
@@ -80,26 +81,27 @@ class RubySamlTest < Test::Unit::TestCase
|
|
80
81
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
81
82
|
end
|
82
83
|
|
83
|
-
|
84
|
+
it "raise validation error for wrong request status" do
|
84
85
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, settings)
|
85
86
|
|
86
87
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
87
88
|
end
|
88
89
|
|
89
|
-
|
90
|
+
it "raise validation error when in bad state" do
|
90
91
|
# no settings
|
91
92
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response)
|
92
93
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
93
94
|
end
|
94
95
|
|
95
|
-
|
96
|
+
it "raise validation error when in lack of sp_entity_id setting" do
|
96
97
|
bad_settings = settings
|
97
98
|
bad_settings.issuer = nil
|
99
|
+
bad_settings.sp_entity_id = nil
|
98
100
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_response, bad_settings)
|
99
101
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
100
102
|
end
|
101
103
|
|
102
|
-
|
104
|
+
it "raise error for invalid xml" do
|
103
105
|
logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_response, settings)
|
104
106
|
|
105
107
|
assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate! }
|
@@ -107,10 +109,4 @@ class RubySamlTest < Test::Unit::TestCase
|
|
107
109
|
end
|
108
110
|
|
109
111
|
end
|
110
|
-
|
111
|
-
# logoutresponse fixtures
|
112
|
-
def random_id
|
113
|
-
"_#{UUID.new.generate}"
|
114
|
-
end
|
115
|
-
|
116
112
|
end
|