ruby-saml 1.9.0 → 1.15.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 (160) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/test.yml +43 -0
  3. data/{changelog.md → CHANGELOG.md} +72 -1
  4. data/LICENSE +2 -1
  5. data/README.md +439 -212
  6. data/UPGRADING.md +149 -0
  7. data/lib/onelogin/ruby-saml/attributes.rb +24 -1
  8. data/lib/onelogin/ruby-saml/authrequest.rb +27 -11
  9. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +285 -184
  10. data/lib/onelogin/ruby-saml/logging.rb +3 -3
  11. data/lib/onelogin/ruby-saml/logoutrequest.rb +27 -12
  12. data/lib/onelogin/ruby-saml/logoutresponse.rb +27 -11
  13. data/lib/onelogin/ruby-saml/metadata.rb +62 -17
  14. data/lib/onelogin/ruby-saml/response.rb +87 -38
  15. data/lib/onelogin/ruby-saml/saml_message.rb +16 -8
  16. data/lib/onelogin/ruby-saml/setting_error.rb +6 -0
  17. data/lib/onelogin/ruby-saml/settings.rb +123 -52
  18. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +33 -31
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +44 -21
  20. data/lib/onelogin/ruby-saml/utils.rb +101 -9
  21. data/lib/onelogin/ruby-saml/version.rb +1 -1
  22. data/lib/xml_security.rb +41 -15
  23. data/ruby-saml.gemspec +49 -13
  24. metadata +71 -308
  25. data/.travis.yml +0 -32
  26. data/test/certificates/certificate1 +0 -12
  27. data/test/certificates/certificate_without_head_foot +0 -1
  28. data/test/certificates/formatted_certificate +0 -14
  29. data/test/certificates/formatted_chained_certificate +0 -42
  30. data/test/certificates/formatted_private_key +0 -12
  31. data/test/certificates/formatted_rsa_private_key +0 -12
  32. data/test/certificates/invalid_certificate1 +0 -1
  33. data/test/certificates/invalid_certificate2 +0 -1
  34. data/test/certificates/invalid_certificate3 +0 -12
  35. data/test/certificates/invalid_chained_certificate1 +0 -1
  36. data/test/certificates/invalid_private_key1 +0 -1
  37. data/test/certificates/invalid_private_key2 +0 -1
  38. data/test/certificates/invalid_private_key3 +0 -10
  39. data/test/certificates/invalid_rsa_private_key1 +0 -1
  40. data/test/certificates/invalid_rsa_private_key2 +0 -1
  41. data/test/certificates/invalid_rsa_private_key3 +0 -10
  42. data/test/certificates/ruby-saml-2.crt +0 -15
  43. data/test/certificates/ruby-saml.crt +0 -14
  44. data/test/certificates/ruby-saml.key +0 -15
  45. data/test/idp_metadata_parser_test.rb +0 -579
  46. data/test/logging_test.rb +0 -62
  47. data/test/logout_requests/invalid_slo_request.xml +0 -6
  48. data/test/logout_requests/slo_request.xml +0 -4
  49. data/test/logout_requests/slo_request.xml.base64 +0 -1
  50. data/test/logout_requests/slo_request_deflated.xml.base64 +0 -1
  51. data/test/logout_requests/slo_request_with_name_id_format.xml +0 -4
  52. data/test/logout_requests/slo_request_with_session_index.xml +0 -5
  53. data/test/logout_responses/logoutresponse_fixtures.rb +0 -67
  54. data/test/logoutrequest_test.rb +0 -226
  55. data/test/logoutresponse_test.rb +0 -402
  56. data/test/metadata/idp_descriptor.xml +0 -26
  57. data/test/metadata/idp_descriptor_2.xml +0 -56
  58. data/test/metadata/idp_descriptor_3.xml +0 -14
  59. data/test/metadata/idp_descriptor_4.xml +0 -72
  60. data/test/metadata/idp_metadata_different_sign_and_encrypt_cert.xml +0 -72
  61. data/test/metadata/idp_metadata_multi_certs.xml +0 -75
  62. data/test/metadata/idp_metadata_multi_signing_certs.xml +0 -52
  63. data/test/metadata/idp_metadata_same_sign_and_encrypt_cert.xml +0 -71
  64. data/test/metadata/idp_multiple_descriptors.xml +0 -53
  65. data/test/metadata/no_idp_descriptor.xml +0 -21
  66. data/test/metadata_test.rb +0 -331
  67. data/test/request_test.rb +0 -323
  68. data/test/response_test.rb +0 -1619
  69. data/test/responses/adfs_response_sha1.xml +0 -46
  70. data/test/responses/adfs_response_sha256.xml +0 -46
  71. data/test/responses/adfs_response_sha384.xml +0 -46
  72. data/test/responses/adfs_response_sha512.xml +0 -46
  73. data/test/responses/adfs_response_xmlns.xml +0 -45
  74. data/test/responses/attackxee.xml +0 -13
  75. data/test/responses/invalids/duplicated_attributes.xml.base64 +0 -1
  76. data/test/responses/invalids/empty_destination.xml.base64 +0 -1
  77. data/test/responses/invalids/empty_nameid.xml.base64 +0 -1
  78. data/test/responses/invalids/encrypted_new_attack.xml.base64 +0 -1
  79. data/test/responses/invalids/invalid_audience.xml.base64 +0 -1
  80. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  81. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  82. data/test/responses/invalids/invalid_signature_position.xml.base64 +0 -1
  83. data/test/responses/invalids/invalid_subjectconfirmation_inresponse.xml.base64 +0 -1
  84. data/test/responses/invalids/invalid_subjectconfirmation_nb.xml.base64 +0 -1
  85. data/test/responses/invalids/invalid_subjectconfirmation_noa.xml.base64 +0 -1
  86. data/test/responses/invalids/invalid_subjectconfirmation_recipient.xml.base64 +0 -1
  87. data/test/responses/invalids/multiple_assertions.xml.base64 +0 -2
  88. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  89. data/test/responses/invalids/no_authnstatement.xml.base64 +0 -1
  90. data/test/responses/invalids/no_conditions.xml.base64 +0 -1
  91. data/test/responses/invalids/no_id.xml.base64 +0 -1
  92. data/test/responses/invalids/no_issuer_assertion.xml.base64 +0 -1
  93. data/test/responses/invalids/no_issuer_response.xml.base64 +0 -1
  94. data/test/responses/invalids/no_nameid.xml.base64 +0 -1
  95. data/test/responses/invalids/no_saml2.xml.base64 +0 -1
  96. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  97. data/test/responses/invalids/no_status.xml.base64 +0 -1
  98. data/test/responses/invalids/no_status_code.xml.base64 +0 -1
  99. data/test/responses/invalids/no_subjectconfirmation_data.xml.base64 +0 -1
  100. data/test/responses/invalids/no_subjectconfirmation_method.xml.base64 +0 -1
  101. data/test/responses/invalids/response_invalid_signed_element.xml.base64 +0 -1
  102. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  103. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  104. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  105. data/test/responses/invalids/status_code_responder.xml.base64 +0 -1
  106. data/test/responses/invalids/status_code_responer_and_msg.xml.base64 +0 -1
  107. data/test/responses/invalids/wrong_spnamequalifier.xml.base64 +0 -1
  108. data/test/responses/no_signature_ns.xml +0 -48
  109. data/test/responses/open_saml_response.xml +0 -56
  110. data/test/responses/response_assertion_wrapped.xml.base64 +0 -93
  111. data/test/responses/response_audience_self_closed_tag.xml.base64 +0 -1
  112. data/test/responses/response_double_status_code.xml.base64 +0 -1
  113. data/test/responses/response_encrypted_attrs.xml.base64 +0 -1
  114. data/test/responses/response_encrypted_nameid.xml.base64 +0 -1
  115. data/test/responses/response_eval.xml +0 -7
  116. data/test/responses/response_no_cert_and_encrypted_attrs.xml +0 -29
  117. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  118. data/test/responses/response_node_text_attack2.xml.base64 +0 -1
  119. data/test/responses/response_node_text_attack3.xml.base64 +0 -1
  120. data/test/responses/response_unsigned_xml_base64 +0 -1
  121. data/test/responses/response_with_ampersands.xml +0 -139
  122. data/test/responses/response_with_ampersands.xml.base64 +0 -93
  123. data/test/responses/response_with_ds_namespace_at_the_root.xml.base64 +0 -1
  124. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  125. data/test/responses/response_with_multiple_attribute_values.xml +0 -67
  126. data/test/responses/response_with_retrieval_method.xml +0 -26
  127. data/test/responses/response_with_saml2_namespace.xml.base64 +0 -102
  128. data/test/responses/response_with_signed_assertion.xml.base64 +0 -66
  129. data/test/responses/response_with_signed_assertion_2.xml.base64 +0 -1
  130. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  131. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  132. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  133. data/test/responses/response_without_attributes.xml.base64 +0 -79
  134. data/test/responses/response_without_reference_uri.xml.base64 +0 -1
  135. data/test/responses/response_wrapped.xml.base64 +0 -150
  136. data/test/responses/signed_message_encrypted_signed_assertion.xml.base64 +0 -1
  137. data/test/responses/signed_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  138. data/test/responses/signed_nameid_in_atts.xml +0 -47
  139. data/test/responses/signed_unqual_nameid_in_atts.xml +0 -47
  140. data/test/responses/simple_saml_php.xml +0 -71
  141. data/test/responses/starfield_response.xml.base64 +0 -1
  142. data/test/responses/test_sign.xml +0 -43
  143. data/test/responses/unsigned_encrypted_adfs.xml +0 -23
  144. data/test/responses/unsigned_message_aes128_encrypted_signed_assertion.xml.base64 +0 -1
  145. data/test/responses/unsigned_message_aes192_encrypted_signed_assertion.xml.base64 +0 -1
  146. data/test/responses/unsigned_message_aes256_encrypted_signed_assertion.xml.base64 +0 -1
  147. data/test/responses/unsigned_message_des192_encrypted_signed_assertion.xml.base64 +0 -1
  148. data/test/responses/unsigned_message_encrypted_assertion_without_saml_namespace.xml.base64 +0 -1
  149. data/test/responses/unsigned_message_encrypted_signed_assertion.xml.base64 +0 -1
  150. data/test/responses/unsigned_message_encrypted_unsigned_assertion.xml.base64 +0 -1
  151. data/test/responses/valid_response.xml.base64 +0 -1
  152. data/test/responses/valid_response_with_formatted_x509certificate.xml.base64 +0 -1
  153. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  154. data/test/saml_message_test.rb +0 -56
  155. data/test/settings_test.rb +0 -329
  156. data/test/slo_logoutrequest_test.rb +0 -448
  157. data/test/slo_logoutresponse_test.rb +0 -199
  158. data/test/test_helper.rb +0 -327
  159. data/test/utils_test.rb +0 -254
  160. 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