ruby-saml 0.8.11 → 0.8.16

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.

Files changed (55) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +3 -1
  3. data/Rakefile +0 -14
  4. data/lib/onelogin/ruby-saml/logoutresponse.rb +9 -51
  5. data/lib/onelogin/ruby-saml/response.rb +121 -30
  6. data/lib/onelogin/ruby-saml/settings.rb +27 -10
  7. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +101 -0
  8. data/lib/onelogin/ruby-saml/utils.rb +92 -0
  9. data/lib/onelogin/ruby-saml/version.rb +1 -1
  10. data/lib/ruby-saml.rb +1 -0
  11. data/lib/xml_security.rb +222 -87
  12. data/test/certificates/certificate.der +0 -0
  13. data/test/certificates/formatted_certificate +14 -0
  14. data/test/certificates/formatted_chained_certificate +42 -0
  15. data/test/certificates/formatted_private_key +12 -0
  16. data/test/certificates/formatted_rsa_private_key +12 -0
  17. data/test/certificates/invalid_certificate1 +1 -0
  18. data/test/certificates/invalid_certificate2 +1 -0
  19. data/test/certificates/invalid_certificate3 +12 -0
  20. data/test/certificates/invalid_chained_certificate1 +1 -0
  21. data/test/certificates/invalid_private_key1 +1 -0
  22. data/test/certificates/invalid_private_key2 +1 -0
  23. data/test/certificates/invalid_private_key3 +10 -0
  24. data/test/certificates/invalid_rsa_private_key1 +1 -0
  25. data/test/certificates/invalid_rsa_private_key2 +1 -0
  26. data/test/certificates/invalid_rsa_private_key3 +10 -0
  27. data/test/certificates/ruby-saml-2.crt +15 -0
  28. data/test/logoutrequest_test.rb +124 -126
  29. data/test/logoutresponse_test.rb +22 -42
  30. data/test/requests/logoutrequest_fixtures.rb +47 -0
  31. data/test/response_test.rb +373 -129
  32. data/test/responses/adfs_response_xmlns.xml +45 -0
  33. data/test/responses/encrypted_new_attack.xml.base64 +1 -0
  34. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +1 -0
  35. data/test/responses/invalids/invalid_issuer_message.xml.base64 +1 -0
  36. data/test/responses/invalids/multiple_signed.xml.base64 +1 -0
  37. data/test/responses/invalids/no_signature.xml.base64 +1 -0
  38. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +51 -0
  39. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +49 -0
  40. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +1 -0
  41. data/test/responses/logoutresponse_fixtures.rb +4 -4
  42. data/test/responses/response_with_concealed_signed_assertion.xml +51 -0
  43. data/test/responses/response_with_doubled_signed_assertion.xml +49 -0
  44. data/test/responses/response_with_signed_assertion_3.xml +30 -0
  45. data/test/responses/response_with_signed_message_and_assertion.xml +34 -0
  46. data/test/responses/response_with_undefined_recipient.xml.base64 +1 -0
  47. data/test/responses/response_wrapped.xml.base64 +150 -0
  48. data/test/responses/valid_response.xml.base64 +1 -0
  49. data/test/responses/valid_response_without_x509certificate.xml.base64 +1 -0
  50. data/test/settings_test.rb +111 -5
  51. data/test/slo_logoutrequest_test.rb +66 -0
  52. data/test/test_helper.rb +110 -41
  53. data/test/utils_test.rb +201 -11
  54. data/test/xml_security_test.rb +359 -68
  55. metadata +77 -7
@@ -0,0 +1 @@
1
+ PD94bWwgdmVyc2lvbj0iMS4wIj8+DQo8c2FtbHA6UmVzcG9uc2UgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgSUQ9InBmeGJjODI2YWZkLWU5ZmUtZDNmYi1kODc0LWM0NzAwYzNlZjBjOCIgVmVyc2lvbj0iMi4wIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIiBEZXN0aW5hdGlvbj0iaHR0cDovL2FwcC5tdWRhLm5vL3Nzby9jb25zdW1lIiBJblJlc3BvbnNlVG89Il9mYzRhMzRiMC03ZWZiLTAxMmUtY2FhZS03ODJiY2IxM2JiMzgiPjxzYW1sOklzc3Vlcj5odHRwczovL2FwcC5vbmVsb2dpbi5jb20vc2FtbDI8L3NhbWw6SXNzdWVyPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPg0KICA8ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPg0KICAgIDxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz4NCiAgPGRzOlJlZmVyZW5jZSBVUkk9IiNwZnhiYzgyNmFmZC1lOWZlLWQzZmItZDg3NC1jNDcwMGMzZWYwYzgiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIi8+PGRzOkRpZ2VzdFZhbHVlPkl6NFpRbHMzQUpaRGIzczh2Y1VYLzNSYytGUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWU+UWhLSm1vbnlzUDFxbW5hN1MrZUUxTGMycktBampDMk9HclFPZ1NqUHBUb2N1bVE2aFlIa3pUU1pyN3QvSS9LVE9TdkhDUXFEMXJoNGxTMGpEUC9FdUhOQUN0azlZN2xsMlV5Z3U3MkwrYkZ0cVoyOURuOXJMa1NkR3JpK0k3SGh4TDM2N2RmQVNTaDYrc3k3V2V2RWRrTWZ3ZURRMkFYL3NhNkJCR2d6N1RFPTwvZHM6U2lnbmF0dXJlVmFsdWU+DQo8ZHM6S2V5SW5mbz48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlDR3pDQ0FZUUNDUUNOTmNRWG9tMzJWREFOQmdrcWhraUc5dzBCQVFVRkFEQlNNUXN3Q1FZRFZRUUdFd0pWVXpFTE1Ba0dBMVVFQ0JNQ1NVNHhGVEFUQmdOVkJBY1RERWx1WkdsaGJtRndiMnhwY3pFUk1BOEdBMVVFQ2hNSVQyNWxURzluYVc0eEREQUtCZ05WQkFzVEEwVnVaekFlRncweE5EQTBNak14T0RReE1ERmFGdzB4TlRBME1qTXhPRFF4TURGYU1GSXhDekFKQmdOVkJBWVRBbFZUTVFzd0NRWURWUVFJRXdKSlRqRVZNQk1HQTFVRUJ4TU1TVzVrYVdGdVlYQnZiR2x6TVJFd0R3WURWUVFLRXdoUGJtVk1iMmRwYmpFTU1Bb0dBMVVFQ3hNRFJXNW5NSUdmTUEwR0NTcUdTSWIzRFFFQkFRVUFBNEdOQURDQmlRS0JnUURvNm0rUVp2WVEveEwwRWxMZ3VwSzFRRGNZTDRmNVBja3dzTmdTOXBVdlY3ZnpUcUNIazhUaEx4VGs0Mk1RMk1jSnNPZVVKVlA3MjhLaHltakZDcXhnUDRWdXdSazlycEFsMCttaHk2TVBkeWp5QTZHMTRqckRXUzY1eXNMY2hLNHQvdndwRUR6MFNRbEVvRzFrTXpsbFNtN3paUzNYcmVnQTdEak5hVVlRcXdJREFRQUJNQTBHQ1NxR1NJYjNEUUVCQlFVQUE0R0JBTE0ydkdDaVEvdm0rYTZ2NDArVlgyemRxSEEyUS8xdkYxaWJReko1NE1KQ09WV3ZzK3ZRWGZaRmhkbTBPUE0ySXJEVTdvcXZLUHFQNnhPQWVKSzZIMHlQN000WUwzZmF0U3ZJWW1tZnlYQzlrdDNTdnovTnlySHpQaFVuSjB5ZS9zVVNYeG56UXh3Y20vOVB3QXFyUWFBM1FwUWtINTd5YkYvT29yeVBlKzJoPC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8+PC9zYW1scDpTdGF0dXM+PHNhbWw6QXNzZXJ0aW9uIHhtbG5zOnhzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSIgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgVmVyc2lvbj0iMi4wIiBJRD0icGZ4OTUxNmIwZjMtNDUzNi0xMGY2LWM2ZmEtOWRkNTIzZTE0OThjIiBJc3N1ZUluc3RhbnQ9IjIwMTQtMDYtMDRUMDI6MjI6MDJaIj48c2FtbDpJc3N1ZXI+aHR0cHM6Ly9hcHAub25lbG9naW4uY29tL3NhbWwyPC9zYW1sOklzc3Vlcj48c2FtbDpTdWJqZWN0PjxzYW1sOk5hbWVJRCBGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMTpuYW1laWQtZm9ybWF0OmVtYWlsQWRkcmVzcyI+dGVzdEBvbmVsb2dpbi5jb208L3NhbWw6TmFtZUlEPjxzYW1sOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBOb3RPbk9yQWZ0ZXI9IjIwMzAtMDYtMDRUMDI6Mjc6MDJaIiBSZWNpcGllbnQ9InJlY2lwaWVudCIvPjwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDpTdWJqZWN0PjxzYW1sOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDExLTA2LTA0VDAyOjE3OjAyWiIgTm90T25PckFmdGVyPSIyMDMwLTA2LTA0VDAyOjI3OjAyWiI+PHNhbWw6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDpBdWRpZW5jZT5odHRwczovL3NvbWVvbmUuZXhhbXBsZS5jb20vYXVkaWVuY2U8L3NhbWw6QXVkaWVuY2U+PC9zYW1sOkF1ZGllbmNlUmVzdHJpY3Rpb24+PC9zYW1sOkNvbmRpdGlvbnM+PHNhbWw6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE0LTA2LTA0VDAyOjIyOjAyWiIgU2Vzc2lvbk5vdE9uT3JBZnRlcj0iMjAzMC0wNi0wNVQwMjoyMjowMloiIFNlc3Npb25JbmRleD0iXzE2ZjU3MGZiYzAzMTUwMDdhMDM1NWRmZWE2YjNjNDZjIj48c2FtbDpBdXRobkNvbnRleHQ+PHNhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWw6QXV0aG5Db250ZXh0Q2xhc3NSZWY+PC9zYW1sOkF1dGhuQ29udGV4dD48L3NhbWw6QXV0aG5TdGF0ZW1lbnQ+PC9zYW1sOkFzc2VydGlvbj48L3NhbWxwOlJlc3BvbnNlPg==
@@ -0,0 +1 @@
1
+ pVZdd9o4EH3fc/Y/+LiPOcayDTb4BLoU0oSWfBDTbpuXPbI0Bie25Egi0Pz6lQ04kJI03X2CGY/u3LkjjXT8fpVnxgMImXLWNZ0GMt/3/vzjWOI8K8JrkAVnEgwdxGRYOrvmQrCQY5nKkOEcZKhIGPXPx6HbQCGWEoTSUObOkuL1NYXgihOemcZo2DWLZBWTtuvjhFrQScCiXhJbtB00LdIMECIeJIi0TePrlrPG0EulXMCISYWZ0i7kNC3kW6g5RW7ouiFyb0xjCFKlDKtq1VypIrRtXBSNfEFxg3FbSm4TXe4iBw3ItsVPedf8JyFN7DVjZAWg6SDHBYtgDFbQdmMSO14ce22zV8kWVlxEr8wgNyk4g4zPUtYgPLfLIPfY3o09pjKM0pkmtxBbtamsWS6Xy8bSa3Axs12EkI06to6hMp29M3W3DGO7HuiIJbyCG2DGWUpwlj5WJZ+DmnNq9LMZF6ma5y+AO7aDSnALVsQiTpO9M+0qxVOSiuQb4fa4CoktOcfOBrHEu4YEBDACxpfrUdd899b2VyVOBWYy4SKX++bvsQL2oJtTALXktjhN8PcAD6p2bP/McZjO9C78L+JthHsC+YqzBfRGj82bSSa9/qebYezJ9gP58s32rsnRx0m3IrAbXDlqydfms21TN3i9YjL//Cnn7Ie8cu5zhoPoCE6cMXHF5/7t7cC9PBWTy1l0e1VMOVnkE3/+/ezucRrdiEDZI/vz9DJ6OBtM7oeOmDezCN0Or+yTxdlFf6DuOt+DLHO//JgtAnd8FH9U9zduZ8g6YnwX0VORHo2Cs/lq7PkBTfpRNPeP5I/gb3g4oXfnyRKGE7f/TR8i/8OH09ljMD3p1uXs8NejbM/b20y2SGlT7lsDTsGolr0+sGQVHUYLQkDKqtE/g4b97SjcHOfVS8fZsb+djyMyhxybdWz662ArrcYdgZ9m4XqMdlqOH6PEs5otz7cclPgW8RNsdShtuR44zU6bvGlw/o+xVhnRIr4FojbWhdZzNDQ+6iOB1ctCOw2n8qTUSqrQUJecZn1KRSl6T+lN/ddu/k3mNfx+5gFnSVpilN1Yn73XO0zyMAYsQJgvAw2xwsYFV5fsUvQTBaJUz0M76gXra+caSFqkUMortn/rTXMI+dmnDQUdQdPysyyzfgCtClQNc55SOpuUb6C13aULmpazQF92SqRknX7vS91wyXPQgjdghfMig6rneBO0YVyveWbvodvPyqnzqTkrTxDkWiCjMn9xoUd6J2iEF6ptHQgdMQorfZ07ftIKUBIT5DkthAKMvFaLJoD92CNNn5i7pDRVBSt1wDXI9INHz9Peq28iEpIyTruv9M+SC3qlnzy6s0Cr26HgQtWCHQA/8G3PV4tWe7ejp55M27dM718=
@@ -1,12 +1,12 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class SettingsTest < Test::Unit::TestCase
3
+ class SettingsTest < Minitest::Test
4
4
 
5
- context "Settings" do
6
- setup do
5
+ describe "Settings" do
6
+ before do
7
7
  @settings = OneLogin::RubySaml::Settings.new
8
8
  end
9
- should "should provide getters and settings" do
9
+ it "should provide getters and settings" do
10
10
  accessors = [
11
11
  :assertion_consumer_service_url, :issuer, :sp_entity_id, :sp_name_qualifier,
12
12
  :idp_sso_target_url, :idp_cert_fingerprint, :name_identifier_format,
@@ -22,7 +22,7 @@ class SettingsTest < Test::Unit::TestCase
22
22
  end
23
23
  end
24
24
 
25
- should "create settings from hash" do
25
+ it "create settings from hash" do
26
26
 
27
27
  config = {
28
28
  :assertion_consumer_service_url => "http://app.muda.no/sso",
@@ -42,6 +42,112 @@ class SettingsTest < Test::Unit::TestCase
42
42
  end
43
43
  end
44
44
 
45
+ describe "#get_idp_cert" do
46
+ it "returns nil when the cert is an empty string" do
47
+ @settings.idp_cert = ""
48
+ assert_nil @settings.get_idp_cert
49
+ end
50
+
51
+ it "returns nil when the cert is nil" do
52
+ @settings.idp_cert = nil
53
+ assert_nil @settings.get_idp_cert
54
+ end
55
+
56
+ it "returns the certificate when it is valid" do
57
+ @settings.idp_cert = ruby_saml_cert_text
58
+ assert @settings.get_idp_cert.kind_of? OpenSSL::X509::Certificate
59
+ end
60
+
61
+ it "raises when the certificate is not valid" do
62
+ # formatted but invalid cert
63
+ @settings.idp_cert = read_certificate("formatted_certificate")
64
+ assert_raises(OpenSSL::X509::CertificateError) {
65
+ @settings.get_idp_cert
66
+ }
67
+ end
68
+ end
69
+
70
+ describe "#get_sp_cert" do
71
+ it "returns nil when the cert is an empty string" do
72
+ @settings.certificate = ""
73
+ assert_nil @settings.get_sp_cert
74
+ end
75
+
76
+ it "returns nil when the cert is nil" do
77
+ @settings.certificate = nil
78
+ assert_nil @settings.get_sp_cert
79
+ end
80
+
81
+ it "returns the certificate when it is valid" do
82
+ @settings.certificate = ruby_saml_cert_text
83
+ assert @settings.get_sp_cert.kind_of? OpenSSL::X509::Certificate
84
+ end
85
+
86
+ it "raises when the certificate is not valid" do
87
+ # formatted but invalid cert
88
+ @settings.certificate = read_certificate("formatted_certificate")
89
+ assert_raises(OpenSSL::X509::CertificateError) {
90
+ @settings.get_sp_cert
91
+ }
92
+ end
93
+ end
94
+
95
+ describe "#get_sp_key" do
96
+ it "returns nil when the private key is an empty string" do
97
+ @settings.private_key = ""
98
+ assert_nil @settings.get_sp_key
99
+ end
100
+
101
+ it "returns nil when the private key is nil" do
102
+ @settings.private_key = nil
103
+ assert_nil @settings.get_sp_key
104
+ end
105
+
106
+ it "returns the private key when it is valid" do
107
+ @settings.private_key = ruby_saml_key_text
108
+ assert @settings.get_sp_key.kind_of? OpenSSL::PKey::RSA
109
+ end
110
+
111
+ it "raises when the private key is not valid" do
112
+ # formatted but invalid rsa private key
113
+ @settings.private_key = read_certificate("formatted_rsa_private_key")
114
+ assert_raises(OpenSSL::PKey::RSAError) {
115
+ @settings.get_sp_key
116
+ }
117
+ end
118
+
119
+ end
120
+
121
+ describe "#get_fingerprint" do
122
+ it "get the fingerprint value when cert and fingerprint in settings are nil" do
123
+ @settings.idp_cert_fingerprint = nil
124
+ @settings.idp_cert = nil
125
+ fingerprint = @settings.get_fingerprint
126
+ assert_nil fingerprint
127
+ end
128
+
129
+ it "get the fingerprint value when there is a cert at the settings" do
130
+ @settings.idp_cert_fingerprint = nil
131
+ @settings.idp_cert = ruby_saml_cert_text
132
+ fingerprint = @settings.get_fingerprint
133
+ assert fingerprint.downcase == ruby_saml_cert_fingerprint.downcase
134
+ end
135
+
136
+ it "get the fingerprint value when there is a fingerprint at the settings" do
137
+ @settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
138
+ @settings.idp_cert = nil
139
+ fingerprint = @settings.get_fingerprint
140
+ assert fingerprint.downcase == ruby_saml_cert_fingerprint.downcase
141
+ end
142
+
143
+ it "get the fingerprint value when there are cert and fingerprint at the settings" do
144
+ @settings.idp_cert_fingerprint = ruby_saml_cert_fingerprint
145
+ @settings.idp_cert = ruby_saml_cert_text
146
+ fingerprint = @settings.get_fingerprint
147
+ assert fingerprint.downcase == ruby_saml_cert_fingerprint.downcase
148
+ end
149
+ end
150
+
45
151
  end
46
152
 
47
153
  end
@@ -0,0 +1,66 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), "requests/logoutrequest_fixtures"))
3
+
4
+ class SloLogoutrequestTest < Minitest::Test
5
+
6
+ describe "SloLogoutrequest" do
7
+
8
+ describe "#new" do
9
+ it "raise an exception when request is initialized with nil" do
10
+ assert_raises(ArgumentError) { OneLogin::RubySaml::SloLogoutrequest.new(nil) }
11
+ end
12
+ it "default to empty settings" do
13
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request)
14
+ assert logoutrequest.settings.nil?
15
+ end
16
+ it "accept constructor-injected settings" do
17
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request, settings)
18
+ assert !logoutrequest.settings.nil?
19
+ end
20
+ it "accept constructor-injected options" do
21
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request, nil, { :foo => :bar} )
22
+ assert !logoutrequest.options.empty?
23
+ end
24
+ it "support base64 encoded requests" do
25
+ expected_request = valid_request
26
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(Base64.encode64(expected_request), settings)
27
+
28
+ assert_equal expected_request, logoutrequest.request
29
+ end
30
+ end
31
+
32
+ describe "#validate" do
33
+ it "validate the request" do
34
+ in_relation_to_request_id = random_id
35
+ settings.idp_entity_id = "https://example.com/idp"
36
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request({:uuid => in_relation_to_request_id}), settings)
37
+
38
+ assert logoutrequest.validate
39
+
40
+ assert_equal settings.idp_entity_id, logoutrequest.issuer
41
+
42
+ assert_equal "testuser@example.com", logoutrequest.nameid
43
+
44
+ assert_equal "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", logoutrequest.nameid_format
45
+ end
46
+
47
+ end
48
+
49
+ describe "#validate!" do
50
+ it "validates good requests" do
51
+ in_relation_to_request_id = random_id
52
+
53
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request({:uuid => in_relation_to_request_id}), settings)
54
+
55
+ logoutrequest.validate!
56
+ end
57
+
58
+ it "raise error for invalid xml" do
59
+ logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(invalid_xml_request, settings)
60
+
61
+ assert_raises(OneLogin::RubySaml::ValidationError) { logoutrequest.validate! }
62
+ end
63
+ end
64
+
65
+ end
66
+ end
@@ -1,17 +1,22 @@
1
1
  require 'rubygems'
2
- require 'test/unit'
3
2
  require 'minitest/autorun'
4
3
  require 'shoulda'
5
4
  require 'mocha/setup'
6
5
  require 'timecop'
7
6
 
7
+ if RUBY_VERSION < '1.9'
8
+ require 'uuid'
9
+ else
10
+ require 'securerandom'
11
+ end
12
+
8
13
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
14
  $LOAD_PATH.unshift(File.dirname(__FILE__))
10
15
  require 'ruby-saml'
11
16
 
12
17
  ENV["ruby-saml/testing"] = "1"
13
18
 
14
- class Test::Unit::TestCase
19
+ class Minitest::Test
15
20
  def fixture(document, base64 = true)
16
21
  response = Dir.glob(File.join(File.dirname(__FILE__), "responses", "#{document}*")).first
17
22
  if base64 && response =~ /\.xml$/
@@ -21,32 +26,48 @@ class Test::Unit::TestCase
21
26
  end
22
27
  end
23
28
 
29
+ def random_id
30
+ RUBY_VERSION < '1.9' ? "_#{UUID.new.generate}" : "_#{SecureRandom.uuid}"
31
+ end
32
+
33
+ def read_invalid_response(response)
34
+ File.read(File.join(File.dirname(__FILE__), "responses", "invalids", response))
35
+ end
36
+
37
+ def read_response(response)
38
+ File.read(File.join(File.dirname(__FILE__), "responses", response))
39
+ end
40
+
41
+ def read_certificate(certificate)
42
+ File.read(File.join(File.dirname(__FILE__), "certificates", certificate))
43
+ end
44
+
24
45
  def response_document
25
- @response_document ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response1.xml.base64'))
46
+ @response_document ||= read_response('response1.xml.base64')
26
47
  end
27
48
 
28
49
  def response_document_2
29
- @response_document2 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response2.xml.base64'))
50
+ @response_document2 ||= read_response('response2.xml.base64')
30
51
  end
31
52
 
32
53
  def response_document_3
33
- @response_document3 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response3.xml.base64'))
54
+ @response_document3 ||= read_response('response3.xml.base64')
34
55
  end
35
56
 
36
57
  def response_document_4
37
- @response_document4 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response4.xml.base64'))
58
+ @response_document4 ||= read_response('response4.xml.base64')
38
59
  end
39
60
 
40
61
  def response_document_5
41
- @response_document5 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response5.xml.base64'))
62
+ @response_document5 ||= read_response('response5.xml.base64')
42
63
  end
43
64
 
44
65
  def r1_response_document_6
45
- @response_document6 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'r1_response6.xml.base64'))
66
+ @response_document6 ||= read_response('r1_response6.xml.base64')
46
67
  end
47
68
 
48
69
  def ampersands_response
49
- @ampersands_resposne ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'response_with_ampersands.xml.base64'))
70
+ @ampersands_resposne ||= read_response('response_with_ampersands.xml.base64')
50
71
  end
51
72
 
52
73
  def response_document_6
@@ -56,6 +77,22 @@ class Test::Unit::TestCase
56
77
  Base64.encode64(doc)
57
78
  end
58
79
 
80
+ def response_document_wrapped
81
+ @response_document_wrapped ||= read_response("response_wrapped.xml.base64")
82
+ end
83
+
84
+ def response_document_valid_signed
85
+ response_document_valid_signed ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'valid_response.xml.base64'))
86
+ end
87
+
88
+ def response_document_valid_signed_without_x509certificate
89
+ @response_document_valid_signed_without_x509certificate ||= read_response("valid_response_without_x509certificate.xml.base64")
90
+ end
91
+
92
+ def response_document_without_recipient
93
+ @response_document_without_recipient ||= read_response("response_with_undefined_recipient.xml.base64")
94
+ end
95
+
59
96
  def wrapped_response_2
60
97
  @wrapped_response_2 ||= File.read(File.join(File.dirname(__FILE__), 'responses', 'wrapped_response_2.xml.base64'))
61
98
  end
@@ -64,12 +101,24 @@ class Test::Unit::TestCase
64
101
  @signature_fingerprint1 ||= "C5:19:85:D9:47:F1:BE:57:08:20:25:05:08:46:EB:27:F6:CA:B7:83"
65
102
  end
66
103
 
104
+ def signature_fingerprint_valid_res
105
+ @signature_fingerprint1 ||= "4b68c453c7d994aad9025c99d5efcf566287fe8d"
106
+ end
107
+
67
108
  def signature_1
68
- @signature1 ||= File.read(File.join(File.dirname(__FILE__), 'certificates', 'certificate1'))
109
+ @signature1 ||= read_certificate('certificate1')
69
110
  end
70
111
 
71
112
  def r1_signature_2
72
- @signature2 ||= File.read(File.join(File.dirname(__FILE__), 'certificates', 'r1_certificate2_base64'))
113
+ @signature2 ||= read_certificate('r1_certificate2_base64')
114
+ end
115
+
116
+ def valid_cert
117
+ @signature_valid_cert ||= read_certificate('ruby-saml.crt')
118
+ end
119
+
120
+ def valid_key
121
+ @signature_valid_cert ||= read_certificate('ruby-saml.key')
73
122
  end
74
123
 
75
124
  def response_with_multiple_attribute_statements
@@ -79,40 +128,60 @@ class Test::Unit::TestCase
79
128
  def response_multiple_attr_values
80
129
  @response_multiple_attr_values = OneLogin::RubySaml::Response.new(fixture(:response_with_multiple_attribute_values))
81
130
  end
82
- end
83
131
 
84
- def ruby_saml_cert_text
85
- read_certificate("ruby-saml.crt")
86
- end
132
+ def ruby_saml_cert
133
+ @ruby_saml_cert ||= OpenSSL::X509::Certificate.new(ruby_saml_cert_text)
134
+ end
87
135
 
88
- def ruby_saml_key_text
89
- read_certificate("ruby-saml.key")
90
- end
136
+ def ruby_saml_cert2
137
+ @ruby_saml_cert2 ||= OpenSSL::X509::Certificate.new(ruby_saml_cert_text2)
138
+ end
91
139
 
92
- def read_certificate(certificate)
93
- File.read(File.join(File.dirname(__FILE__), "certificates", certificate))
94
- end
140
+ def ruby_saml_cert_fingerprint
141
+ @ruby_saml_cert_fingerprint ||= Digest::SHA1.hexdigest(ruby_saml_cert.to_der).scan(/../).join(":")
142
+ end
95
143
 
96
- def decode_saml_request_payload(unauth_url)
97
- payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
98
- decoded = Base64.decode64(payload)
144
+ def ruby_saml_cert_text
145
+ read_certificate("ruby-saml.crt")
146
+ end
99
147
 
100
- zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
101
- inflated = zstream.inflate(decoded)
102
- zstream.finish
103
- zstream.close
104
- inflated
105
- end
148
+ def ruby_saml_cert_text2
149
+ read_certificate("ruby-saml-2.crt")
150
+ end
151
+
152
+ def ruby_saml_key_text
153
+ read_certificate("ruby-saml.key")
154
+ end
106
155
 
107
- # decodes a base64 encoded SAML response for use in SloLogoutresponse tests
108
- #
109
- def decode_saml_response_payload(unauth_url)
110
- payload = CGI.unescape(unauth_url.split("SAMLResponse=").last)
111
- decoded = Base64.decode64(payload)
112
-
113
- zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
114
- inflated = zstream.inflate(decoded)
115
- zstream.finish
116
- zstream.close
117
- inflated
156
+ def ruby_saml_key
157
+ @ruby_saml_key ||= OpenSSL::PKey::RSA.new(ruby_saml_key_text)
158
+ end
159
+
160
+ def read_certificate(certificate)
161
+ File.read(File.join(File.dirname(__FILE__), "certificates", certificate))
162
+ end
163
+
164
+ def decode_saml_request_payload(unauth_url)
165
+ payload = CGI.unescape(unauth_url.split("SAMLRequest=").last)
166
+ decoded = Base64.decode64(payload)
167
+
168
+ zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
169
+ inflated = zstream.inflate(decoded)
170
+ zstream.finish
171
+ zstream.close
172
+ inflated
173
+ end
174
+
175
+ # decodes a base64 encoded SAML response for use in SloLogoutresponse tests
176
+ #
177
+ def decode_saml_response_payload(unauth_url)
178
+ payload = CGI.unescape(unauth_url.split("SAMLResponse=").last)
179
+ decoded = Base64.decode64(payload)
180
+
181
+ zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
182
+ inflated = zstream.inflate(decoded)
183
+ zstream.finish
184
+ zstream.close
185
+ inflated
186
+ end
118
187
  end
@@ -1,41 +1,231 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class UtilsTest < Test::Unit::TestCase
4
- context "Utils" do
5
- context 'element_text' do
6
- should 'returns the element text' do
3
+ class UtilsTest < Minitest::Test
4
+ describe "Utils" do
5
+
6
+ describe "format_cert" do
7
+ let(:formatted_certificate) {read_certificate("formatted_certificate")}
8
+ let(:formatted_chained_certificate) {read_certificate("formatted_chained_certificate")}
9
+
10
+ it "returns empty string when the cert is an empty string" do
11
+ cert = ""
12
+ assert_equal "", OneLogin::RubySaml::Utils.format_cert(cert)
13
+ end
14
+
15
+ it "returns nil when the cert is nil" do
16
+ cert = nil
17
+ assert_nil OneLogin::RubySaml::Utils.format_cert(cert)
18
+ end
19
+
20
+ it "returns the certificate when it is valid" do
21
+ assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(formatted_certificate)
22
+ end
23
+
24
+ it "reformats the certificate when there are spaces and no line breaks" do
25
+ invalid_certificate1 = read_certificate("invalid_certificate1")
26
+ assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate1)
27
+ end
28
+
29
+ it "reformats the certificate when there are spaces and no headers" do
30
+ invalid_certificate2 = read_certificate("invalid_certificate2")
31
+ assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate2)
32
+ end
33
+
34
+ it "returns the cert when it's encoded" do
35
+ encoded_certificate = read_certificate("certificate.der")
36
+ assert_equal encoded_certificate, OneLogin::RubySaml::Utils.format_cert(encoded_certificate)
37
+ end
38
+
39
+ it "reformats the certificate when there line breaks and no headers" do
40
+ invalid_certificate3 = read_certificate("invalid_certificate3")
41
+ assert_equal formatted_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_certificate3)
42
+ end
43
+
44
+ it "returns the chained certificate when it is a valid chained certificate" do
45
+ assert_equal formatted_chained_certificate, OneLogin::RubySaml::Utils.format_cert(formatted_chained_certificate)
46
+ end
47
+
48
+ it "reformats the chained certificate when there are spaces and no line breaks" do
49
+ invalid_chained_certificate1 = read_certificate("invalid_chained_certificate1")
50
+ assert_equal formatted_chained_certificate, OneLogin::RubySaml::Utils.format_cert(invalid_chained_certificate1)
51
+ end
52
+
53
+ end
54
+
55
+ describe "format_private_key" do
56
+ let(:formatted_private_key) do
57
+ read_certificate("formatted_private_key")
58
+ end
59
+
60
+ it "returns empty string when the private key is an empty string" do
61
+ private_key = ""
62
+ assert_equal "", OneLogin::RubySaml::Utils.format_private_key(private_key)
63
+ end
64
+
65
+ it "returns nil when the private key is nil" do
66
+ private_key = nil
67
+ assert_nil OneLogin::RubySaml::Utils.format_private_key(private_key)
68
+ end
69
+
70
+ it "returns the private key when it is valid" do
71
+ assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(formatted_private_key)
72
+ end
73
+
74
+ it "reformats the private key when there are spaces and no line breaks" do
75
+ invalid_private_key1 = read_certificate("invalid_private_key1")
76
+ assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_private_key1)
77
+ end
78
+
79
+ it "reformats the private key when there are spaces and no headers" do
80
+ invalid_private_key2 = read_certificate("invalid_private_key2")
81
+ assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_private_key2)
82
+ end
83
+
84
+ it "reformats the private key when there line breaks and no headers" do
85
+ invalid_private_key3 = read_certificate("invalid_private_key3")
86
+ assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_private_key3)
87
+ end
88
+
89
+ describe "an RSA public key" do
90
+ let(:formatted_rsa_private_key) do
91
+ read_certificate("formatted_rsa_private_key")
92
+ end
93
+
94
+ it "returns the private key when it is valid" do
95
+ assert_equal formatted_rsa_private_key, OneLogin::RubySaml::Utils.format_private_key(formatted_rsa_private_key)
96
+ end
97
+
98
+ it "reformats the private key when there are spaces and no line breaks" do
99
+ invalid_rsa_private_key1 = read_certificate("invalid_rsa_private_key1")
100
+ assert_equal formatted_rsa_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_rsa_private_key1)
101
+ end
102
+
103
+ it "reformats the private key when there are spaces and no headers" do
104
+ invalid_rsa_private_key2 = read_certificate("invalid_rsa_private_key2")
105
+ assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_rsa_private_key2)
106
+ end
107
+
108
+ it "reformats the private key when there line breaks and no headers" do
109
+ invalid_rsa_private_key3 = read_certificate("invalid_rsa_private_key3")
110
+ assert_equal formatted_private_key, OneLogin::RubySaml::Utils.format_private_key(invalid_rsa_private_key3)
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "build_query" do
116
+ it "returns the query string" do
117
+ params = {}
118
+ params[:type] = "SAMLRequest"
119
+ params[:data] = "PHNhbWxwOkF1dGhuUmVxdWVzdCBEZXN0aW5hdGlvbj0naHR0cDovL2V4YW1wbGUuY29tP2ZpZWxkPXZhbHVlJyBJRD0nXzk4NmUxZDEwLWVhY2ItMDEzMi01MGRkLTAwOTBmNWRlZGQ3NycgSXNzdWVJbnN0YW50PScyMDE1LTA2LTAxVDIwOjM0OjU5WicgVmVyc2lvbj0nMi4wJyB4bWxuczpzYW1sPSd1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uJyB4bWxuczpzYW1scD0ndXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sJy8+"
120
+ params[:relay_state] = "http://example.com"
121
+ params[:sig_alg] = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
122
+ query_string = OneLogin::RubySaml::Utils.build_query(params)
123
+ assert_equal "SAMLRequest=PHNhbWxwOkF1dGhuUmVxdWVzdCBEZXN0aW5hdGlvbj0naHR0cDovL2V4YW1wbGUuY29tP2ZpZWxkPXZhbHVlJyBJRD0nXzk4NmUxZDEwLWVhY2ItMDEzMi01MGRkLTAwOTBmNWRlZGQ3NycgSXNzdWVJbnN0YW50PScyMDE1LTA2LTAxVDIwOjM0OjU5WicgVmVyc2lvbj0nMi4wJyB4bWxuczpzYW1sPSd1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uJyB4bWxuczpzYW1scD0ndXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sJy8%2B&RelayState=http%3A%2F%2Fexample.com&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1", query_string
124
+ end
125
+ end
126
+
127
+ describe "#status_error_msg" do
128
+ it "returns a error msg with a status message" do
129
+ error_msg = "The status code of the Logout Response was not Success"
130
+ status_code = "urn:oasis:names:tc:SAML:2.0:status:Requester"
131
+ status_message = "The request could not be performed due to an error on the part of the requester."
132
+ status_error_msg = OneLogin::RubySaml::Utils.status_error_msg(error_msg, status_code, status_message)
133
+ assert_equal = "The status code of the Logout Response was not Success, was Requester -> The request could not be performed due to an error on the part of the requester.", status_error_msg
134
+
135
+ status_error_msg2 = OneLogin::RubySaml::Utils.status_error_msg(error_msg, status_code)
136
+ assert_equal = "The status code of the Logout Response was not Success, was Requester", status_error_msg2
137
+
138
+ status_error_msg3 = OneLogin::RubySaml::Utils.status_error_msg(error_msg)
139
+ assert_equal = "The status code of the Logout Response was not Success", status_error_msg3
140
+ end
141
+ end
142
+
143
+ describe 'uri_match' do
144
+ it 'matches two urls' do
145
+ destination = 'http://www.example.com/test?var=stuff'
146
+ settings = 'http://www.example.com/test?var=stuff'
147
+ assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
148
+ end
149
+
150
+ it 'fails to match two urls' do
151
+ destination = 'http://www.example.com/test?var=stuff'
152
+ settings = 'http://www.example.com/othertest?var=stuff'
153
+ assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
154
+ end
155
+
156
+ it "matches two URLs if the scheme case doesn't match" do
157
+ destination = 'http://www.example.com/test?var=stuff'
158
+ settings = 'HTTP://www.example.com/test?var=stuff'
159
+ assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
160
+ end
161
+
162
+ it "matches two URLs if the host case doesn't match" do
163
+ destination = 'http://www.EXAMPLE.com/test?var=stuff'
164
+ settings = 'http://www.example.com/test?var=stuff'
165
+ assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
166
+ end
167
+
168
+ it "fails to match two URLs if the path case doesn't match" do
169
+ destination = 'http://www.example.com/TEST?var=stuff'
170
+ settings = 'http://www.example.com/test?var=stuff'
171
+ assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
172
+ end
173
+
174
+ it "fails to match two URLs if the query case doesn't match" do
175
+ destination = 'http://www.example.com/test?var=stuff'
176
+ settings = 'http://www.example.com/test?var=STUFF'
177
+ assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
178
+ end
179
+
180
+ it 'matches two non urls' do
181
+ destination = 'stuff'
182
+ settings = 'stuff'
183
+ assert OneLogin::RubySaml::Utils.uri_match?(destination, settings)
184
+ end
185
+
186
+ it "fails to match two non urls" do
187
+ destination = 'stuff'
188
+ settings = 'not stuff'
189
+ assert !OneLogin::RubySaml::Utils.uri_match?(destination, settings)
190
+ end
191
+ end
192
+
193
+ describe 'element_text' do
194
+ it 'returns the element text' do
7
195
  element = REXML::Document.new('<element>element text</element>').elements.first
8
196
  assert_equal 'element text', OneLogin::RubySaml::Utils.element_text(element)
9
197
  end
10
198
 
11
- should 'returns all segments of the element text' do
199
+ it 'returns all segments of the element text' do
12
200
  element = REXML::Document.new('<element>element <!-- comment -->text</element>').elements.first
13
201
  assert_equal 'element text', OneLogin::RubySaml::Utils.element_text(element)
14
202
  end
15
203
 
16
- should 'returns normalized element text' do
204
+ it 'returns normalized element text' do
17
205
  element = REXML::Document.new('<element>element &amp; text</element>').elements.first
18
206
  assert_equal 'element & text', OneLogin::RubySaml::Utils.element_text(element)
19
207
  end
20
208
 
21
- should 'returns the CDATA element text' do
209
+ it 'returns the CDATA element text' do
22
210
  element = REXML::Document.new('<element><![CDATA[element & text]]></element>').elements.first
23
211
  assert_equal 'element & text', OneLogin::RubySaml::Utils.element_text(element)
24
212
  end
25
213
 
26
- should 'returns the element text with newlines and additional whitespace' do
214
+ it 'returns the element text with newlines and additional whitespace' do
27
215
  element = REXML::Document.new("<element> element \n text </element>").elements.first
28
216
  assert_equal " element \n text ", OneLogin::RubySaml::Utils.element_text(element)
29
217
  end
30
218
 
31
- should 'returns nil when element is nil' do
219
+ it 'returns nil when element is nil' do
32
220
  assert_nil OneLogin::RubySaml::Utils.element_text(nil)
33
221
  end
34
222
 
35
- should 'returns empty string when element has no text' do
223
+ it 'returns empty string when element has no text' do
36
224
  element = REXML::Document.new('<element></element>').elements.first
37
225
  assert_equal '', OneLogin::RubySaml::Utils.element_text(element)
38
226
  end
227
+
228
+
39
229
  end
40
230
  end
41
- end
231
+ end