ruby-saml 1.9.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +30 -14
  3. data/README.md +108 -22
  4. data/changelog.md +38 -0
  5. data/lib/onelogin/ruby-saml/attributes.rb +24 -1
  6. data/lib/onelogin/ruby-saml/authrequest.rb +23 -6
  7. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +239 -171
  8. data/lib/onelogin/ruby-saml/logging.rb +3 -3
  9. data/lib/onelogin/ruby-saml/logoutrequest.rb +20 -5
  10. data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -9
  11. data/lib/onelogin/ruby-saml/metadata.rb +11 -3
  12. data/lib/onelogin/ruby-saml/response.rb +67 -21
  13. data/lib/onelogin/ruby-saml/saml_message.rb +12 -2
  14. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  15. data/lib/onelogin/ruby-saml/settings.rb +73 -7
  16. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +20 -1
  17. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +38 -16
  18. data/lib/onelogin/ruby-saml/utils.rb +74 -1
  19. data/lib/onelogin/ruby-saml/version.rb +1 -1
  20. data/lib/xml_security.rb +34 -6
  21. data/ruby-saml.gemspec +15 -7
  22. metadata +36 -278
  23. data/test/certificates/certificate1 +0 -12
  24. data/test/certificates/certificate_without_head_foot +0 -1
  25. data/test/certificates/formatted_certificate +0 -14
  26. data/test/certificates/formatted_chained_certificate +0 -42
  27. data/test/certificates/formatted_private_key +0 -12
  28. data/test/certificates/formatted_rsa_private_key +0 -12
  29. data/test/certificates/invalid_certificate1 +0 -1
  30. data/test/certificates/invalid_certificate2 +0 -1
  31. data/test/certificates/invalid_certificate3 +0 -12
  32. data/test/certificates/invalid_chained_certificate1 +0 -1
  33. data/test/certificates/invalid_private_key1 +0 -1
  34. data/test/certificates/invalid_private_key2 +0 -1
  35. data/test/certificates/invalid_private_key3 +0 -10
  36. data/test/certificates/invalid_rsa_private_key1 +0 -1
  37. data/test/certificates/invalid_rsa_private_key2 +0 -1
  38. data/test/certificates/invalid_rsa_private_key3 +0 -10
  39. data/test/certificates/ruby-saml-2.crt +0 -15
  40. data/test/certificates/ruby-saml.crt +0 -14
  41. data/test/certificates/ruby-saml.key +0 -15
  42. data/test/idp_metadata_parser_test.rb +0 -579
  43. data/test/logging_test.rb +0 -62
  44. data/test/logout_requests/invalid_slo_request.xml +0 -6
  45. data/test/logout_requests/slo_request.xml +0 -4
  46. data/test/logout_requests/slo_request.xml.base64 +0 -1
  47. data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
  48. data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
  49. data/test/logout_requests/slo_request_with_session_index.xml +0 -5
  50. data/test/logout_responses/logoutresponse_fixtures.rb +0 -67
  51. data/test/logoutrequest_test.rb +0 -226
  52. data/test/logoutresponse_test.rb +0 -402
  53. data/test/metadata/idp_descriptor.xml +0 -26
  54. data/test/metadata/idp_descriptor_2.xml +0 -56
  55. data/test/metadata/idp_descriptor_3.xml +0 -14
  56. data/test/metadata/idp_descriptor_4.xml +0 -72
  57. data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
  58. data/test/metadata/idp_metadata_multi_certs.xml +0 -75
  59. data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
  60. data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
  61. data/test/metadata/idp_multiple_descriptors.xml +0 -53
  62. data/test/metadata/no_idp_descriptor.xml +0 -21
  63. data/test/metadata_test.rb +0 -331
  64. data/test/request_test.rb +0 -323
  65. data/test/response_test.rb +0 -1619
  66. data/test/responses/adfs_response_sha1.xml +0 -46
  67. data/test/responses/adfs_response_sha256.xml +0 -46
  68. data/test/responses/adfs_response_sha384.xml +0 -46
  69. data/test/responses/adfs_response_sha512.xml +0 -46
  70. data/test/responses/adfs_response_xmlns.xml +0 -45
  71. data/test/responses/attackxee.xml +0 -13
  72. data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
  73. data/test/responses/invalids/empty_destination.xml.base64 +0 -1
  74. data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
  75. data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
  76. data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
  77. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  78. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  79. data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
  80. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
  81. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
  82. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
  83. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
  84. data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
  85. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  86. data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
  87. data/test/responses/invalids/no_conditions.xml.base64 +0 -1
  88. data/test/responses/invalids/no_id.xml.base64 +0 -1
  89. data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
  90. data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
  91. data/test/responses/invalids/no_nameid.xml.base64 +0 -1
  92. data/test/responses/invalids/no_saml2.xml.base64 +0 -1
  93. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  94. data/test/responses/invalids/no_status.xml.base64 +0 -1
  95. data/test/responses/invalids/no_status_code.xml.base64 +0 -1
  96. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
  97. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
  98. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
  99. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  100. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  101. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  102. data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
  103. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
  104. data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
  105. data/test/responses/no_signature_ns.xml +0 -48
  106. data/test/responses/open_saml_response.xml +0 -56
  107. data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
  108. data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
  109. data/test/responses/response_double_status_code.xml.base64 +0 -1
  110. data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
  111. data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
  112. data/test/responses/response_eval.xml +0 -7
  113. data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
  114. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  115. data/test/responses/response_node_text_attack2.xml.base64 +0 -1
  116. data/test/responses/response_node_text_attack3.xml.base64 +0 -1
  117. data/test/responses/response_unsigned_xml_base64 +0 -1
  118. data/test/responses/response_with_ampersands.xml +0 -139
  119. data/test/responses/response_with_ampersands.xml.base64 +0 -93
  120. data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
  121. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  122. data/test/responses/response_with_multiple_attribute_values.xml +0 -67
  123. data/test/responses/response_with_retrieval_method.xml +0 -26
  124. data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
  125. data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
  126. data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
  127. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  128. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  129. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  130. data/test/responses/response_without_attributes.xml.base64 +0 -79
  131. data/test/responses/response_without_reference_uri.xml.base64 +0 -1
  132. data/test/responses/response_wrapped.xml.base64 +0 -150
  133. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
  134. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  135. data/test/responses/signed_nameid_in_atts.xml +0 -47
  136. data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
  137. data/test/responses/simple_saml_php.xml +0 -71
  138. data/test/responses/starfield_response.xml.base64 +0 -1
  139. data/test/responses/test_sign.xml +0 -43
  140. data/test/responses/unsigned_encrypted_adfs.xml +0 -23
  141. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
  142. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
  143. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
  144. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
  145. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
  146. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
  147. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  148. data/test/responses/valid_response.xml.base64 +0 -1
  149. data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
  150. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  151. data/test/saml_message_test.rb +0 -56
  152. data/test/settings_test.rb +0 -329
  153. data/test/slo_logoutrequest_test.rb +0 -448
  154. data/test/slo_logoutresponse_test.rb +0 -199
  155. data/test/test_helper.rb +0 -327
  156. data/test/utils_test.rb +0 -254
  157. data/test/xml_security_test.rb +0 -421
data/test/logging_test.rb DELETED
@@ -1,62 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
-
3
- require 'onelogin/ruby-saml/logging'
4
-
5
- class LoggingTest < Minitest::Test
6
-
7
- describe "Logging" do
8
- before do
9
- OneLogin::RubySaml::Logging.logger = nil
10
- end
11
-
12
- after do
13
- OneLogin::RubySaml::Logging.logger = ::TEST_LOGGER
14
- end
15
-
16
- describe "given no specific logging setup" do
17
- it "prints to stdout" do
18
- OneLogin::RubySaml::Logging::DEFAULT_LOGGER.expects(:debug).with('hi mom')
19
- OneLogin::RubySaml::Logging.debug('hi mom')
20
- end
21
- end
22
-
23
- describe "given a Rails app" do
24
- let(:logger) { mock('Logger') }
25
-
26
- before do
27
- ::Rails = mock('Rails module')
28
- ::Rails.stubs(:logger).returns(logger)
29
- end
30
-
31
- after do
32
- Object.instance_eval { remove_const(:Rails) }
33
- end
34
-
35
- it "delegates to Rails" do
36
- logger.expects(:debug).with('hi mom')
37
- logger.expects(:info).with('sup?')
38
-
39
- OneLogin::RubySaml::Logging.debug('hi mom')
40
- OneLogin::RubySaml::Logging.info('sup?')
41
- end
42
- end
43
-
44
- describe "given a specific Logger" do
45
- let(:logger) { mock('Logger') }
46
-
47
- before { OneLogin::RubySaml::Logging.logger = logger }
48
-
49
- after do
50
- OneLogin::RubySaml::Logging.logger = ::TEST_LOGGER
51
- end
52
-
53
- it "delegates to the object" do
54
- logger.expects(:debug).with('hi mom')
55
- logger.expects(:info).with('sup?')
56
-
57
- OneLogin::RubySaml::Logging.debug('hi mom')
58
- OneLogin::RubySaml::Logging.info('sup?')
59
- end
60
- end
61
- end
62
- end
@@ -1,6 +0,0 @@
1
- <samlp:LogoutRequest Version='2.0' ID='_c0348950-935b-0131-1060-782bcb56fcaa' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol' IssueInstant='2014-03-21T19:20:13'>
2
- <saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>https://app.onelogin.com/saml/metadata/SOMEACCOUNT</saml:Issuer>
3
- <saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>https://app.onelogin.com/saml/metadata/SOMEACCOUNT</saml:Issuer>
4
- <saml:NameID xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>someone@example.org</saml:NameID>
5
- <saml:NameID xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>someone2@example.org</saml:NameID>
6
- </samlp:LogoutRequest>
@@ -1,4 +0,0 @@
1
- <samlp:LogoutRequest Version='2.0' ID='_c0348950-935b-0131-1060-782bcb56fcaa' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol' IssueInstant='2014-03-21T19:20:13'>
2
- <saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>https://app.onelogin.com/saml/metadata/SOMEACCOUNT</saml:Issuer>
3
- <saml:NameID xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>someone@example.org</saml:NameID>
4
- </samlp:LogoutRequest>
@@ -1 +0,0 @@
1
- PHNhbWxwOkxvZ291dFJlcXVlc3QgVmVyc2lvbj0nMi4wJyBJRD0nX2MwMzQ4OTUwLTkzNWItMDEzMS0xMDYwLTc4MmJjYjU2ZmNhYScgeG1sbnM6c2FtbHA9J3VybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCcgSXNzdWVJbnN0YW50PScyMDE0LTAzLTIxVDE5OjIwOjEzJz4NCiAgPHNhbWw6SXNzdWVyIHhtbG5zOnNhbWw9J3VybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24nPmh0dHBzOi8vYXBwLm9uZWxvZ2luLmNvbS9zYW1sL21ldGFkYXRhL1NPTUVBQ0NPVU5UPC9zYW1sOklzc3Vlcj4NCiAgPHNhbWw6TmFtZUlEIHhtbG5zOnNhbWw9J3VybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24nPnNvbWVvbmVAZXhhbXBsZS5vcmc8L3NhbWw6TmFtZUlEPg0KPC9zYW1scDpMb2dvdXRSZXF1ZXN0Pg==
@@ -1 +0,0 @@
1
- ndG7asMwFIDhvdB38KZJlmTHaSxs05B0COQCTdq1yKrqGqxLdWTI41dJOpgOHToKDv93DqpA6MHxre3sGJ7V16ggJK/KQ29NjbKUomSzrtGbpPlsURYUl3nRYspyhhmdU/ywyFrZFvMPKQRKznowwK/JGo3ecCugB26EVsCD5MflbstjlDtvg5V2iHWAUW0MBGFCBCmbYZrjjJ1YyTPKWY6a+7skqS5Rfh32E+ZvRQAoH+IlqPkMwQEnRDiXWqMG2/UmlVaTS4VoFcS7CIIcD7un5Wp1eNmfKjIhJzvsI7NZ/2cHsFpF+1GdhXaDSq3vfpBbMyK396//aL4B
@@ -1,4 +0,0 @@
1
- <samlp:LogoutRequest Version='2.0' ID='_c0348950-935b-0131-1060-782bcb56fcaa' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol' IssueInstant='2014-03-21T19:20:13'>
2
- <saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>https://app.onelogin.com/saml/metadata/SOMEACCOUNT</saml:Issuer>
3
- <saml:NameID xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion' Format='urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'>someone@example.org</saml:NameID>
4
- </samlp:LogoutRequest>
@@ -1,5 +0,0 @@
1
- <samlp:LogoutRequest Version='2.0' ID='_c0348950-935b-0131-1060-782bcb56fcaa' xmlns:samlp='urn:oasis:names:tc:SAML:2.0:protocol' IssueInstant='2014-03-21T19:20:13'>
2
- <saml:Issuer xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>https://app.onelogin.com/saml/metadata/SOMEACCOUNT</saml:Issuer>
3
- <saml:NameID xmlns:saml='urn:oasis:names:tc:SAML:2.0:assertion'>someone@example.org</saml:NameID>
4
- <samlp:SessionIndex>_ea853497-c58a-408a-bc23-c849752d9741</samlp:SessionIndex>
5
- </samlp:LogoutRequest>
@@ -1,67 +0,0 @@
1
- #encoding: utf-8
2
-
3
- def default_logout_response_opts
4
- {
5
- :uuid => "_28024690-000e-0130-b6d2-38f6b112be8b",
6
- :issue_instant => Time.now.strftime('%Y-%m-%dT%H:%M:%SZ'),
7
- :settings => settings
8
- }
9
- end
10
-
11
- def valid_logout_response_document(opts = {})
12
- opts = default_logout_response_opts.merge(opts)
13
-
14
- "<samlp:LogoutResponse
15
- xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
16
- ID=\"#{random_id}\" Version=\"2.0\"
17
- IssueInstant=\"#{opts[:issue_instant]}\"
18
- Destination=\"#{opts[:settings].single_logout_service_url}\"
19
- InResponseTo=\"#{opts[:uuid]}\">
20
- <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].issuer}</saml:Issuer>
21
- <samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">
22
- <samlp:StatusCode xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
23
- Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\">
24
- </samlp:StatusCode>
25
- </samlp:Status>
26
- </samlp:LogoutResponse>"
27
- end
28
-
29
- def unsuccessful_logout_response_document(opts = {})
30
- opts = default_logout_response_opts.merge(opts)
31
-
32
- "<samlp:LogoutResponse
33
- xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
34
- ID=\"#{random_id}\" Version=\"2.0\"
35
- IssueInstant=\"#{opts[:issue_instant]}\"
36
- Destination=\"#{opts[:settings].single_logout_service_url}\"
37
- InResponseTo=\"#{opts[:uuid]}\">
38
- <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].issuer}</saml:Issuer>
39
- <samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">
40
- <samlp:StatusCode xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
41
- Value=\"urn:oasis:names:tc:SAML:2.0:status:Requester\">
42
- </samlp:StatusCode>
43
- </samlp:Status>
44
- </samlp:LogoutResponse>"
45
- end
46
-
47
- def invalid_xml_logout_response_document
48
- "<samlp:SomethingAwful
49
- xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
50
- ID=\"#{random_id}\" Version=\"2.0\">
51
- </samlp:SomethingAwful>"
52
- end
53
-
54
- def settings
55
- @settings ||= OneLogin::RubySaml::Settings.new(
56
- {
57
- :assertion_consumer_service_url => "http://app.muda.no/sso/consume",
58
- :single_logout_service_url => "http://app.muda.no/sso/consume_logout",
59
- :issuer => "http://app.muda.no",
60
- :sp_name_qualifier => "http://sso.muda.no",
61
- :idp_sso_target_url => "http://sso.muda.no/sso",
62
- :idp_slo_target_url => "http://sso.muda.no/slo",
63
- :idp_cert_fingerprint => "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
64
- :name_identifier_format => "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
65
- }
66
- )
67
- end
@@ -1,226 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
-
3
- require 'onelogin/ruby-saml/logoutrequest'
4
-
5
- class RequestTest < Minitest::Test
6
-
7
- describe "Logoutrequest" do
8
- let(:settings) { OneLogin::RubySaml::Settings.new }
9
-
10
- before do
11
- settings.idp_slo_target_url = "http://unauth.com/logout"
12
- settings.name_identifier_value = "f00f00"
13
- end
14
-
15
- it "create the deflated SAMLRequest URL parameter" do
16
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
17
- assert_match /^http:\/\/unauth\.com\/logout\?SAMLRequest=/, unauth_url
18
-
19
- inflated = decode_saml_request_payload(unauth_url)
20
- assert_match /^<samlp:LogoutRequest/, inflated
21
- end
22
-
23
- it "support additional params" do
24
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :hello => nil })
25
- assert_match /&hello=$/, unauth_url
26
-
27
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :foo => "bar" })
28
- assert_match /&foo=bar$/, unauth_url
29
- end
30
-
31
- it "RelayState cases" do
32
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :RelayState => nil })
33
- assert !unauth_url.include?('RelayState')
34
-
35
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :RelayState => "http://example.com" })
36
- assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
37
-
38
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { 'RelayState' => nil })
39
- assert !unauth_url.include?('RelayState')
40
-
41
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { 'RelayState' => "http://example.com" })
42
- assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
43
- end
44
-
45
- it "set sessionindex" do
46
- settings.idp_slo_target_url = "http://example.com"
47
- sessionidx = OneLogin::RubySaml::Utils.uuid
48
- settings.sessionindex = sessionidx
49
-
50
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :nameid => "there" })
51
- inflated = decode_saml_request_payload(unauth_url)
52
-
53
- assert_match /<samlp:SessionIndex/, inflated
54
- assert_match %r(#{sessionidx}</samlp:SessionIndex>), inflated
55
- end
56
-
57
- it "set name_identifier_value" do
58
- settings.name_identifier_format = "transient"
59
- name_identifier_value = "abc123"
60
- settings.name_identifier_value = name_identifier_value
61
-
62
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings, { :nameid => "there" })
63
- inflated = decode_saml_request_payload(unauth_url)
64
-
65
- assert_match /<saml:NameID/, inflated
66
- assert_match %r(#{name_identifier_value}</saml:NameID>), inflated
67
- end
68
-
69
- describe "when the target url doesn't contain a query string" do
70
- it "create the SAMLRequest parameter correctly" do
71
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
72
- assert_match /^http:\/\/unauth.com\/logout\?SAMLRequest/, unauth_url
73
- end
74
- end
75
-
76
- describe "when the target url contains a query string" do
77
- it "create the SAMLRequest parameter correctly" do
78
- settings.idp_slo_target_url = "http://example.com?field=value"
79
-
80
- unauth_url = OneLogin::RubySaml::Logoutrequest.new.create(settings)
81
- assert_match /^http:\/\/example.com\?field=value&SAMLRequest/, unauth_url
82
- end
83
- end
84
-
85
- describe "consumation of logout may need to track the transaction" do
86
- it "have access to the request uuid" do
87
- settings.idp_slo_target_url = "http://example.com?field=value"
88
-
89
- unauth_req = OneLogin::RubySaml::Logoutrequest.new
90
- unauth_url = unauth_req.create(settings)
91
-
92
- inflated = decode_saml_request_payload(unauth_url)
93
- assert_match %r[ID='#{unauth_req.uuid}'], inflated
94
- end
95
- end
96
-
97
- describe "when the settings indicate to sign (embedded) logout request" do
98
-
99
- before do
100
- # sign the logout request
101
- settings.security[:logout_requests_signed] = true
102
- settings.security[:embed_sign] = true
103
- settings.certificate = ruby_saml_cert_text
104
- settings.private_key = ruby_saml_key_text
105
- end
106
-
107
- it "created a signed logout request" do
108
- settings.compress_request = true
109
-
110
- unauth_req = OneLogin::RubySaml::Logoutrequest.new
111
- unauth_url = unauth_req.create(settings)
112
-
113
- inflated = decode_saml_request_payload(unauth_url)
114
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
115
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
116
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
117
- end
118
-
119
- it "create a signed logout request with 256 digest and signature method" do
120
- settings.compress_request = false
121
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
122
- settings.security[:digest_method] = XMLSecurity::Document::SHA256
123
-
124
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
125
- request_xml = Base64.decode64(params["SAMLRequest"])
126
-
127
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
128
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'/>], request_xml
129
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha256'/>], request_xml
130
- end
131
-
132
- it "create a signed logout request with 512 digest and signature method RSA_SHA384" do
133
- settings.compress_request = false
134
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
135
- settings.security[:digest_method] = XMLSecurity::Document::SHA512
136
-
137
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings)
138
- request_xml = Base64.decode64(params["SAMLRequest"])
139
-
140
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], request_xml
141
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'/>], request_xml
142
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2001/04/xmlenc#sha512'/>], request_xml
143
- end
144
- end
145
-
146
- describe "#create_params when the settings indicate to sign the logout request" do
147
-
148
- let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
149
-
150
- before do
151
- # sign the logout request
152
- settings.security[:logout_requests_signed] = true
153
- settings.security[:embed_sign] = false
154
- settings.certificate = ruby_saml_cert_text
155
- settings.private_key = ruby_saml_key_text
156
- end
157
-
158
- it "create a signature parameter with RSA_SHA1 / SHA1 and validate it" do
159
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
160
-
161
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
162
- assert params['SAMLRequest']
163
- assert params[:RelayState]
164
- assert params['Signature']
165
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
166
-
167
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
168
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
169
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
170
-
171
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
172
- assert_equal signature_algorithm, OpenSSL::Digest::SHA1
173
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
174
- end
175
-
176
- it "create a signature parameter with RSA_SHA256 / SHA256 and validate it" do
177
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
178
-
179
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
180
- assert params['Signature']
181
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
182
-
183
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
184
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
185
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
186
-
187
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
188
- assert_equal signature_algorithm, OpenSSL::Digest::SHA256
189
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
190
- end
191
-
192
- it "create a signature parameter with RSA_SHA384 / SHA384 and validate it" do
193
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
194
-
195
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
196
- assert params['Signature']
197
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA384
198
-
199
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
200
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
201
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
202
-
203
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
204
- assert_equal signature_algorithm, OpenSSL::Digest::SHA384
205
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
206
- end
207
-
208
- it "create a signature parameter with RSA_SHA512 / SHA512 and validate it" do
209
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA512
210
-
211
- params = OneLogin::RubySaml::Logoutrequest.new.create_params(settings, :RelayState => 'http://example.com')
212
- assert params['Signature']
213
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA512
214
-
215
- query_string = "SAMLRequest=#{CGI.escape(params['SAMLRequest'])}"
216
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
217
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
218
-
219
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
220
- assert_equal signature_algorithm, OpenSSL::Digest::SHA512
221
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
222
- end
223
-
224
- end
225
- end
226
- end
@@ -1,402 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
-
3
- require 'onelogin/ruby-saml/logoutresponse'
4
- require 'logout_responses/logoutresponse_fixtures'
5
-
6
- class RubySamlTest < Minitest::Test
7
-
8
- describe "Logoutresponse" do
9
-
10
- let(:valid_logout_response_without_settings) { OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document) }
11
- let(:valid_logout_response) { OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings) }
12
-
13
- describe "#new" do
14
- it "raise an exception when response is initialized with nil" do
15
- assert_raises(ArgumentError) { OneLogin::RubySaml::Logoutresponse.new(nil) }
16
- end
17
- it "default to empty settings" do
18
- assert_nil valid_logout_response_without_settings.settings
19
- end
20
- it "accept constructor-injected settings" do
21
- refute_nil valid_logout_response.settings
22
- end
23
- it "accept constructor-injected options" do
24
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, nil, { :foo => :bar} )
25
- assert !logoutresponse.options.empty?
26
- end
27
- it "support base64 encoded responses" do
28
- generated_logout_response = valid_logout_response_document
29
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(Base64.encode64(generated_logout_response), settings)
30
- assert_equal generated_logout_response, logoutresponse.response
31
- end
32
- end
33
-
34
- describe "#validate_structure" do
35
- it "invalidates when the logout response has an invalid xml" do
36
- settings.soft = true
37
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_logout_response_document, settings)
38
- assert !logoutresponse.send(:validate_structure)
39
- assert_includes logoutresponse.errors, "Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd"
40
- end
41
-
42
- it "raise when the logout response has an invalid xml" do
43
- settings.soft = false
44
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(invalid_xml_logout_response_document, settings)
45
- assert_raises OneLogin::RubySaml::ValidationError do
46
- logoutresponse.send(:validate_structure)
47
- end
48
- end
49
- end
50
-
51
- describe "#validate" do
52
- describe "when soft=true" do
53
- before do
54
- settings.soft = true
55
- end
56
-
57
- it "validate the logout response" do
58
- in_relation_to_request_id = random_id
59
- opts = { :matches_request_id => in_relation_to_request_id}
60
-
61
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings, opts)
62
-
63
- assert logoutresponse.validate
64
-
65
- assert_equal settings.issuer, logoutresponse.issuer
66
- assert_equal in_relation_to_request_id, logoutresponse.in_response_to
67
-
68
- assert logoutresponse.success?
69
- assert_empty logoutresponse.errors
70
- end
71
-
72
- it "validate the logout response extended" do
73
- in_relation_to_request_id = random_id
74
- settings.idp_entity_id = 'http://app.muda.no'
75
- opts = { :matches_request_id => in_relation_to_request_id}
76
-
77
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings, opts)
78
- assert logoutresponse.validate
79
- assert_equal in_relation_to_request_id, logoutresponse.in_response_to
80
- assert logoutresponse.success?
81
- assert_empty logoutresponse.errors
82
- end
83
-
84
- it "invalidate logout response when initiated with blank" do
85
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new("", settings)
86
- assert !logoutresponse.validate
87
- assert_includes logoutresponse.errors, "Blank logout response"
88
- end
89
-
90
- it "invalidate logout response when initiated with no idp cert or fingerprint" do
91
- settings.idp_cert_fingerprint = nil
92
- settings.idp_cert = nil
93
- settings.idp_cert_multi = nil
94
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings)
95
- assert !logoutresponse.validate
96
- assert_includes logoutresponse.errors, "No fingerprint or certificate on settings of the logout response"
97
- end
98
-
99
- it "invalidate logout response with wrong id when given option :matches_request_id" do
100
- expected_request_id = "_some_other_expected_uuid"
101
- opts = { :matches_request_id => expected_request_id}
102
-
103
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings, opts)
104
-
105
- assert !logoutresponse.validate
106
- refute_equal expected_request_id, logoutresponse.in_response_to
107
- assert_includes logoutresponse.errors, "The InResponseTo of the Logout Response: #{logoutresponse.in_response_to}, does not match the ID of the Logout Request sent by the SP: #{expected_request_id}"
108
- end
109
-
110
- it "invalidate logout response with wrong request status" do
111
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
112
-
113
- assert !logoutresponse.success?
114
- assert !logoutresponse.validate
115
- assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
116
- assert_includes logoutresponse.errors, "The status code of the Logout Response was not Success, was Requester"
117
- end
118
-
119
- it "invalidate logout response when in lack of issuer setting" do
120
- bad_settings = settings
121
- bad_settings.issuer = nil
122
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, bad_settings)
123
- assert !logoutresponse.validate
124
- assert_includes logoutresponse.errors, "No issuer in settings of the logout response"
125
- end
126
-
127
- it "invalidate logout response with wrong issuer" do
128
- in_relation_to_request_id = random_id
129
- settings.idp_entity_id = 'http://invalid.issuer.example.com/'
130
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings)
131
- assert !logoutresponse.validate
132
- assert_includes logoutresponse.errors, "Doesn't match the issuer, expected: <#{logoutresponse.settings.idp_entity_id}>, but was: <http://app.muda.no>"
133
- end
134
-
135
- it "collect errors when collect_errors=true" do
136
- settings.idp_entity_id = 'http://invalid.issuer.example.com/'
137
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
138
- collect_errors = true
139
- assert !logoutresponse.validate(collect_errors)
140
- assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
141
- assert_includes logoutresponse.errors, "Doesn't match the issuer, expected: <#{logoutresponse.settings.idp_entity_id}>, but was: <http://app.muda.no>"
142
- end
143
-
144
- end
145
-
146
- describe "when soft=false" do
147
- before do
148
- settings.soft = false
149
- end
150
-
151
- it "validates good logout response" do
152
- in_relation_to_request_id = random_id
153
-
154
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings)
155
- assert logoutresponse.validate
156
- assert_empty logoutresponse.errors
157
- end
158
-
159
- it "raises validation error when response initiated with blank" do
160
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new("", settings)
161
-
162
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
163
- assert_includes logoutresponse.errors, "Blank logout response"
164
- end
165
-
166
- it "raises validation error when initiated with no idp cert or fingerprint" do
167
- settings.idp_cert_fingerprint = nil
168
- settings.idp_cert = nil
169
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings)
170
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
171
- assert_includes logoutresponse.errors, "No fingerprint or certificate on settings of the logout response"
172
- end
173
-
174
- it "raises validation error when matching for wrong request id" do
175
-
176
- expected_request_id = "_some_other_expected_id"
177
- opts = { :matches_request_id => expected_request_id}
178
-
179
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document, settings, opts)
180
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
181
- assert_includes logoutresponse.errors, "The InResponseTo of the Logout Response: #{logoutresponse.in_response_to}, does not match the ID of the Logout Request sent by the SP: #{expected_request_id}"
182
- end
183
-
184
- it "raise validation error for wrong request status" do
185
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
186
-
187
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
188
- assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
189
- end
190
-
191
- it "raise validation error when in bad state" do
192
- # no settings
193
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
194
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
195
- assert_includes logoutresponse.errors, "Bad status code. Expected <urn:oasis:names:tc:SAML:2.0:status:Success>, but was: <urn:oasis:names:tc:SAML:2.0:status:Requester>"
196
- end
197
-
198
- it "raise validation error when in lack of issuer setting" do
199
- settings.issuer = nil
200
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(unsuccessful_logout_response_document, settings)
201
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
202
- assert_includes logoutresponse.errors, "No issuer in settings of the logout response"
203
- end
204
-
205
- it "raise validation error when logout response with wrong issuer" do
206
- in_relation_to_request_id = random_id
207
- settings.idp_entity_id = 'http://invalid.issuer.example.com/'
208
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(valid_logout_response_document({:uuid => in_relation_to_request_id}), settings)
209
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.validate }
210
- assert_includes logoutresponse.errors, "Doesn't match the issuer, expected: <#{logoutresponse.settings.idp_entity_id}>, but was: <http://app.muda.no>"
211
- end
212
- end
213
-
214
- describe "#validate_signature" do
215
- let (:params) { OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, random_id, "Custom Logout Message", :RelayState => 'http://example.com') }
216
-
217
- before do
218
- settings.soft = true
219
- settings.idp_slo_target_url = "http://example.com?field=value"
220
- settings.security[:logout_responses_signed] = true
221
- settings.security[:embed_sign] = false
222
- settings.certificate = ruby_saml_cert_text
223
- settings.private_key = ruby_saml_key_text
224
- settings.idp_cert = ruby_saml_cert_text
225
- end
226
-
227
- it "return true when no idp_cert is provided and option :relax_signature_validation is present" do
228
- settings.idp_cert = nil
229
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
230
- params['RelayState'] = params[:RelayState]
231
- options = {}
232
- options[:get_params] = params
233
- options[:relax_signature_validation] = true
234
- logoutresponse_sign_test = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
235
- assert logoutresponse_sign_test.send(:validate_signature)
236
- end
237
-
238
- it "return false when no idp_cert is provided and no option :relax_signature_validation is present" do
239
- settings.idp_cert = nil
240
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
241
- params['RelayState'] = params[:RelayState]
242
- options = {}
243
- options[:get_params] = params
244
- logoutresponse_sign_test = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
245
- assert !logoutresponse_sign_test.send(:validate_signature)
246
- end
247
-
248
- it "return true when valid RSA_SHA1 Signature" do
249
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
250
- params['RelayState'] = params[:RelayState]
251
- options = {}
252
- options[:get_params] = params
253
- logoutresponse_sign_test = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
254
- assert logoutresponse_sign_test.send(:validate_signature)
255
- end
256
-
257
- it "return true when valid RSA_SHA256 Signature" do
258
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
259
- params['RelayState'] = params[:RelayState]
260
- options = {}
261
- options[:get_params] = params
262
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
263
- assert logoutresponse.send(:validate_signature)
264
- end
265
-
266
- it "return false when invalid RSA_SHA1 Signature" do
267
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
268
- params['RelayState'] = 'http://invalid.example.com'
269
- options = {}
270
- options[:get_params] = params
271
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
272
- assert !logoutresponse.send(:validate_signature)
273
- end
274
-
275
- it "raise when invalid RSA_SHA1 Signature" do
276
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
277
- settings.soft = false
278
- params['RelayState'] = 'http://invalid.example.com'
279
- options = {}
280
- options[:get_params] = params
281
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
282
-
283
- assert_raises(OneLogin::RubySaml::ValidationError) { logoutresponse.send(:validate_signature) }
284
- assert logoutresponse.errors.include? "Invalid Signature on Logout Response"
285
- end
286
-
287
- it "raise when get_params encoding differs from what this library generates" do
288
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
289
- settings.soft = false
290
- options = {}
291
- options[:get_params] = params
292
- options[:get_params]['RelayState'] = 'http://example.com'
293
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
294
- # Assemble query string.
295
- query = OneLogin::RubySaml::Utils.build_query(
296
- :type => 'SAMLResponse',
297
- :data => params['SAMLResponse'],
298
- :relay_state => params['RelayState'],
299
- :sig_alg => params['SigAlg']
300
- )
301
- # Modify the query string so that it encodes the same values,
302
- # but with different percent-encoding. Sanity-check that they
303
- # really are equialent before moving on.
304
- original_query = query.dup
305
- query.gsub!("example", "ex%61mple")
306
- refute_equal(query, original_query)
307
- assert_equal(CGI.unescape(query), CGI.unescape(original_query))
308
- # Make normalised signature based on our modified params.
309
- sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
310
- signature = settings.get_sp_key.sign(sign_algorithm.new, query)
311
- params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
312
- # Re-create the Logoutresponse based on these modified parameters,
313
- # and ask it to validate the signature. It will do it incorrectly,
314
- # because it will compute it based on re-encoded query parameters,
315
- # rather than their original encodings.
316
- options[:get_params] = params
317
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
318
- assert_raises(OneLogin::RubySaml::ValidationError, "Invalid Signature on Logout Request") do
319
- logoutresponse.send(:validate_signature)
320
- end
321
- end
322
-
323
- it "return true even if raw_get_params encoding differs from what this library generates" do
324
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
325
- settings.soft = false
326
- options = {}
327
- options[:get_params] = params
328
- options[:get_params]['RelayState'] = 'http://example.com'
329
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
330
- # Assemble query string.
331
- query = OneLogin::RubySaml::Utils.build_query(
332
- :type => 'SAMLResponse',
333
- :data => params['SAMLResponse'],
334
- :relay_state => params['RelayState'],
335
- :sig_alg => params['SigAlg']
336
- )
337
- # Modify the query string so that it encodes the same values,
338
- # but with different percent-encoding. Sanity-check that they
339
- # really are equialent before moving on.
340
- original_query = query.dup
341
- query.gsub!("example", "ex%61mple")
342
- refute_equal(query, original_query)
343
- assert_equal(CGI.unescape(query), CGI.unescape(original_query))
344
- # Make normalised signature based on our modified params.
345
- sign_algorithm = XMLSecurity::BaseDocument.new.algorithm(settings.security[:signature_method])
346
- signature = settings.get_sp_key.sign(sign_algorithm.new, query)
347
- params['Signature'] = Base64.encode64(signature).gsub(/\n/, "")
348
- # Re-create the Logoutresponse based on these modified parameters,
349
- # and ask it to validate the signature. Provide the altered parameter
350
- # in its raw URI-encoded form, so that we don't have to guess the value
351
- # that contributed to the signature.
352
- options[:get_params] = params
353
- options[:get_params].delete("RelayState")
354
- options[:raw_get_params] = {
355
- "RelayState" => "http%3A%2F%2Fex%61mple.com",
356
- }
357
- logoutresponse = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
358
- assert logoutresponse.send(:validate_signature)
359
- end
360
- end
361
-
362
- describe "#validate_signature" do
363
- let (:params) { OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, random_id, "Custom Logout Message", :RelayState => 'http://example.com') }
364
-
365
- before do
366
- settings.soft = true
367
- settings.idp_slo_target_url = "http://example.com?field=value"
368
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
369
- settings.security[:logout_responses_signed] = true
370
- settings.security[:embed_sign] = false
371
- settings.certificate = ruby_saml_cert_text
372
- settings.private_key = ruby_saml_key_text
373
- settings.idp_cert = nil
374
- end
375
-
376
- it "return true when at least a idp_cert is valid" do
377
- params['RelayState'] = params[:RelayState]
378
- options = {}
379
- options[:get_params] = params
380
- settings.idp_cert_multi = {
381
- :signing => [ruby_saml_cert_text2, ruby_saml_cert_text],
382
- :encryption => []
383
- }
384
- logoutresponse_sign_test = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
385
- assert logoutresponse_sign_test.send(:validate_signature)
386
- end
387
-
388
- it "return false when none cert on idp_cert_multi is valid" do
389
- params['RelayState'] = params[:RelayState]
390
- options = {}
391
- options[:get_params] = params
392
- settings.idp_cert_multi = {
393
- :signing => [ruby_saml_cert_text2, ruby_saml_cert_text2],
394
- :encryption => []
395
- }
396
- logoutresponse_sign_test = OneLogin::RubySaml::Logoutresponse.new(params['SAMLResponse'], settings, options)
397
- assert !logoutresponse_sign_test.send(:validate_signature)
398
- end
399
- end
400
- end
401
- end
402
- end