ruby-saml 0.8.16 → 0.9

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 (90) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -6
  4. data/Gemfile +2 -12
  5. data/README.md +363 -35
  6. data/Rakefile +14 -0
  7. data/changelog.md +22 -9
  8. data/lib/onelogin/ruby-saml/attribute_service.rb +34 -0
  9. data/lib/onelogin/ruby-saml/attributes.rb +26 -64
  10. data/lib/onelogin/ruby-saml/authrequest.rb +47 -89
  11. data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
  12. data/lib/onelogin/ruby-saml/logoutrequest.rb +34 -93
  13. data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -24
  14. data/lib/onelogin/ruby-saml/metadata.rb +46 -16
  15. data/lib/onelogin/ruby-saml/response.rb +62 -322
  16. data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
  17. data/lib/onelogin/ruby-saml/settings.rb +54 -121
  18. data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +26 -61
  19. data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -84
  20. data/lib/onelogin/ruby-saml/utils.rb +32 -199
  21. data/lib/onelogin/ruby-saml/version.rb +1 -1
  22. data/lib/ruby-saml.rb +5 -2
  23. data/lib/schemas/{saml20assertion_schema.xsd → saml-schema-assertion-2.0.xsd} +283 -283
  24. data/lib/schemas/saml-schema-authn-context-2.0.xsd +23 -0
  25. data/lib/schemas/saml-schema-authn-context-types-2.0.xsd +821 -0
  26. data/lib/schemas/saml-schema-metadata-2.0.xsd +339 -0
  27. data/lib/schemas/{saml20protocol_schema.xsd → saml-schema-protocol-2.0.xsd} +302 -302
  28. data/lib/schemas/sstc-metadata-attr.xsd +35 -0
  29. data/lib/schemas/sstc-saml-attribute-ext.xsd +25 -0
  30. data/lib/schemas/sstc-saml-metadata-algsupport-v1.0.xsd +41 -0
  31. data/lib/schemas/sstc-saml-metadata-ui-v1.0.xsd +89 -0
  32. data/lib/schemas/{xenc_schema.xsd → xenc-schema.xsd} +1 -11
  33. data/lib/schemas/xml.xsd +287 -0
  34. data/lib/schemas/{xmldsig_schema.xsd → xmldsig-core-schema.xsd} +0 -9
  35. data/lib/xml_security.rb +83 -235
  36. data/ruby-saml.gemspec +1 -0
  37. data/test/idp_metadata_parser_test.rb +54 -0
  38. data/test/logoutrequest_test.rb +68 -144
  39. data/test/logoutresponse_test.rb +43 -25
  40. data/test/metadata_test.rb +87 -0
  41. data/test/request_test.rb +103 -90
  42. data/test/response_test.rb +181 -471
  43. data/test/responses/idp_descriptor.xml +3 -0
  44. data/test/responses/logoutresponse_fixtures.rb +5 -5
  45. data/test/responses/response_no_cert_and_encrypted_attrs.xml +29 -0
  46. data/test/responses/response_with_multiple_attribute_values.xml +1 -1
  47. data/test/responses/slo_request.xml +4 -0
  48. data/test/settings_test.rb +25 -112
  49. data/test/slo_logoutrequest_test.rb +41 -44
  50. data/test/slo_logoutresponse_test.rb +87 -167
  51. data/test/test_helper.rb +27 -102
  52. data/test/xml_security_test.rb +114 -337
  53. metadata +34 -84
  54. data/lib/onelogin/ruby-saml/setting_error.rb +0 -6
  55. data/test/certificates/certificate.der +0 -0
  56. data/test/certificates/formatted_certificate +0 -14
  57. data/test/certificates/formatted_chained_certificate +0 -42
  58. data/test/certificates/formatted_private_key +0 -12
  59. data/test/certificates/formatted_rsa_private_key +0 -12
  60. data/test/certificates/invalid_certificate1 +0 -1
  61. data/test/certificates/invalid_certificate2 +0 -1
  62. data/test/certificates/invalid_certificate3 +0 -12
  63. data/test/certificates/invalid_chained_certificate1 +0 -1
  64. data/test/certificates/invalid_private_key1 +0 -1
  65. data/test/certificates/invalid_private_key2 +0 -1
  66. data/test/certificates/invalid_private_key3 +0 -10
  67. data/test/certificates/invalid_rsa_private_key1 +0 -1
  68. data/test/certificates/invalid_rsa_private_key2 +0 -1
  69. data/test/certificates/invalid_rsa_private_key3 +0 -10
  70. data/test/certificates/ruby-saml-2.crt +0 -15
  71. data/test/requests/logoutrequest_fixtures.rb +0 -47
  72. data/test/responses/encrypted_new_attack.xml.base64 +0 -1
  73. data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
  74. data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
  75. data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
  76. data/test/responses/invalids/no_signature.xml.base64 +0 -1
  77. data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
  78. data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
  79. data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
  80. data/test/responses/response_node_text_attack.xml.base64 +0 -1
  81. data/test/responses/response_with_concealed_signed_assertion.xml +0 -51
  82. data/test/responses/response_with_doubled_signed_assertion.xml +0 -49
  83. data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
  84. data/test/responses/response_with_signed_assertion_3.xml +0 -30
  85. data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
  86. data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
  87. data/test/responses/response_wrapped.xml.base64 +0 -150
  88. data/test/responses/valid_response.xml.base64 +0 -1
  89. data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
  90. data/test/utils_test.rb +0 -231
@@ -0,0 +1,3 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <md:EntityDescriptor entityID="https://example.hello.com/access/saml/idp.xml" validUntil="2014-04-17T18:02:33.910Z" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"><md:IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><md:KeyDescriptor use="signing"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxekNDQXhTZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBRENCaGpFTE1Ba0dBMVVFQmhNQ1FWVXgKRERBS0JnTlZCQWdUQTA1VFZ6RVBNQTBHQTFVRUJ4TUdVM2xrYm1WNU1Rd3dDZ1lEVlFRS0RBTlFTVlF4Q1RBSApCZ05WQkFzTUFERVlNQllHQTFVRUF3d1BiR0YzY21WdVkyVndhWFF1WTI5dE1TVXdJd1lKS29aSWh2Y05BUWtCCkRCWnNZWGR5Wlc1alpTNXdhWFJBWjIxaGFXd3VZMjl0TUI0WERURXlNRFF4T1RJeU5UUXhPRm9YRFRNeU1EUXgKTkRJeU5UUXhPRm93Z1lZeEN6QUpCZ05WQkFZVEFrRlZNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVApCbE41Wkc1bGVURU1NQW9HQTFVRUNnd0RVRWxVTVFrd0J3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psCmJtTmxjR2wwTG1OdmJURWxNQ01HQ1NxR1NJYjNEUUVKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnYKYlRDQm56QU5CZ2txaGtpRzl3MEJBUUVGQUFPQmpRQXdnWWtDZ1lFQXFqaWUzUjJvaStwRGFldndJeXMvbWJVVApubkdsa3h0ZGlrcnExMXZleHd4SmlQTmhtaHFSVzNtVXVKRXpsbElkVkw2RW14R1lUcXBxZjkzSGxoa3NhZUowCjhVZ2pQOVVtTVlyaFZKdTFqY0ZXVjdmei9yKzIxL2F3VG5EVjlzTVlRcXVJUllZeTdiRzByMU9iaXdkb3ZudGsKN2dGSTA2WjB2WmFjREU1Ym9xVUNBd0VBQWFPQ0FTVXdnZ0VoTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRRApBZ1VnTUIwR0ExVWREZ1FXQkJTUk9OOEdKOG8rOGpnRnRqa3R3WmRxeDZCUnlUQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQVRBZEJnbGdoa2dCaHZoQ0FRMEVFQllPVkdWemRDQllOVEE1SUdObGNuUXdnYk1HQTFVZEl3U0IKcXpDQnFJQVVrVGpmQmlmS1B2STRCYlk1TGNHWGFzZWdVY21oZ1l5a2dZa3dnWVl4Q3pBSkJnTlZCQVlUQWtGVgpNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVEJsTjVaRzVsZVRFTU1Bb0dBMVVFQ2d3RFVFbFVNUWt3CkJ3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psYm1ObGNHbDBMbU52YlRFbE1DTUdDU3FHU0liM0RRRUoKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnZiWUlCQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9CZ1FDRQpUQWVKVERTQVc2ejFVRlRWN1FyZWg0VUxGT1JhajkrZUN1RjNLV0RIYyswSVFDajlyZG5ERzRRL3dmNy9yYVEwCkpuUFFDU0NkclBMSmV5b1BIN1FhVHdvYUY3ZHpWdzRMQ3N5TkpURld4NGNNNTBWdzZSNWZET2dpQzhic2ZmUzgKQkptb3VscnJaRE5OVmpHOG1XNmNMeHJZdlZRT3JSVmVjQ0ZJZ3NzQ2JBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
3
+ </ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:KeyDescriptor use="encryption"><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:X509Data><ds:X509Certificate>LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURxekNDQXhTZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBRENCaGpFTE1Ba0dBMVVFQmhNQ1FWVXgKRERBS0JnTlZCQWdUQTA1VFZ6RVBNQTBHQTFVRUJ4TUdVM2xrYm1WNU1Rd3dDZ1lEVlFRS0RBTlFTVlF4Q1RBSApCZ05WQkFzTUFERVlNQllHQTFVRUF3d1BiR0YzY21WdVkyVndhWFF1WTI5dE1TVXdJd1lKS29aSWh2Y05BUWtCCkRCWnNZWGR5Wlc1alpTNXdhWFJBWjIxaGFXd3VZMjl0TUI0WERURXlNRFF4T1RJeU5UUXhPRm9YRFRNeU1EUXgKTkRJeU5UUXhPRm93Z1lZeEN6QUpCZ05WQkFZVEFrRlZNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVApCbE41Wkc1bGVURU1NQW9HQTFVRUNnd0RVRWxVTVFrd0J3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psCmJtTmxjR2wwTG1OdmJURWxNQ01HQ1NxR1NJYjNEUUVKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnYKYlRDQm56QU5CZ2txaGtpRzl3MEJBUUVGQUFPQmpRQXdnWWtDZ1lFQXFqaWUzUjJvaStwRGFldndJeXMvbWJVVApubkdsa3h0ZGlrcnExMXZleHd4SmlQTmhtaHFSVzNtVXVKRXpsbElkVkw2RW14R1lUcXBxZjkzSGxoa3NhZUowCjhVZ2pQOVVtTVlyaFZKdTFqY0ZXVjdmei9yKzIxL2F3VG5EVjlzTVlRcXVJUllZeTdiRzByMU9iaXdkb3ZudGsKN2dGSTA2WjB2WmFjREU1Ym9xVUNBd0VBQWFPQ0FTVXdnZ0VoTUFrR0ExVWRFd1FDTUFBd0N3WURWUjBQQkFRRApBZ1VnTUIwR0ExVWREZ1FXQkJTUk9OOEdKOG8rOGpnRnRqa3R3WmRxeDZCUnlUQVRCZ05WSFNVRUREQUtCZ2dyCkJnRUZCUWNEQVRBZEJnbGdoa2dCaHZoQ0FRMEVFQllPVkdWemRDQllOVEE1SUdObGNuUXdnYk1HQTFVZEl3U0IKcXpDQnFJQVVrVGpmQmlmS1B2STRCYlk1TGNHWGFzZWdVY21oZ1l5a2dZa3dnWVl4Q3pBSkJnTlZCQVlUQWtGVgpNUXd3Q2dZRFZRUUlFd05PVTFjeER6QU5CZ05WQkFjVEJsTjVaRzVsZVRFTU1Bb0dBMVVFQ2d3RFVFbFVNUWt3CkJ3WURWUVFMREFBeEdEQVdCZ05WQkFNTUQyeGhkM0psYm1ObGNHbDBMbU52YlRFbE1DTUdDU3FHU0liM0RRRUoKQVF3V2JHRjNjbVZ1WTJVdWNHbDBRR2R0WVdsc0xtTnZiWUlCQVRBTkJna3Foa2lHOXcwQkFRc0ZBQU9CZ1FDRQpUQWVKVERTQVc2ejFVRlRWN1FyZWg0VUxGT1JhajkrZUN1RjNLV0RIYyswSVFDajlyZG5ERzRRL3dmNy9yYVEwCkpuUFFDU0NkclBMSmV5b1BIN1FhVHdvYUY3ZHpWdzRMQ3N5TkpURld4NGNNNTBWdzZSNWZET2dpQzhic2ZmUzgKQkptb3VscnJaRE5OVmpHOG1XNmNMeHJZdlZRT3JSVmVjQ0ZJZ3NzQ2JBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></md:KeyDescriptor><md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://example.hello.com/access/saml/logout" ResponseLocation="https://example.hello.com/access/saml/logout"/><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat><md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat><md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://example.hello.com/access/saml/login"/></md:IDPSSODescriptor></md:EntityDescriptor>
@@ -15,9 +15,9 @@ def valid_response(opts = {})
15
15
  xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
16
16
  ID=\"#{random_id}\" Version=\"2.0\"
17
17
  IssueInstant=\"#{opts[:issue_instant]}\"
18
- Destination=\"#{opts[:settings].idp_slo_target_url}\"
18
+ Destination=\"#{opts[:settings].single_logout_service_url}\"
19
19
  InResponseTo=\"#{opts[:uuid]}\">
20
- <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].idp_entity_id}</saml:Issuer>
20
+ <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].issuer}</saml:Issuer>
21
21
  <samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">
22
22
  <samlp:StatusCode xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
23
23
  Value=\"urn:oasis:names:tc:SAML:2.0:status:Success\">
@@ -33,9 +33,9 @@ def unsuccessful_response(opts = {})
33
33
  xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
34
34
  ID=\"#{random_id}\" Version=\"2.0\"
35
35
  IssueInstant=\"#{opts[:issue_instant]}\"
36
- Destination=\"#{opts[:settings].idp_slo_target_url}\"
36
+ Destination=\"#{opts[:settings].single_logout_service_url}\"
37
37
  InResponseTo=\"#{opts[:uuid]}\">
38
- <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].idp_entity_id}</saml:Issuer>
38
+ <saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">#{opts[:settings].issuer}</saml:Issuer>
39
39
  <samlp:Status xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\">
40
40
  <samlp:StatusCode xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"
41
41
  Value=\"urn:oasis:names:tc:SAML:2.0:status:Requester\">
@@ -56,7 +56,7 @@ def settings
56
56
  {
57
57
  :assertion_consumer_service_url => "http://app.muda.no/sso/consume",
58
58
  :single_logout_service_url => "http://app.muda.no/sso/consume_logout",
59
- :sp_entity_id => "http://app.muda.no",
59
+ :issuer => "http://app.muda.no",
60
60
  :sp_name_qualifier => "http://sso.muda.no",
61
61
  :idp_sso_target_url => "http://sso.muda.no/sso",
62
62
  :idp_slo_target_url => "http://sso.muda.no/slo",
@@ -0,0 +1,29 @@
1
+ <?xml version="1.0" encoding="UTF-8"?><samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://vmwdemo.socialcast.com/saml/authenticate" ID="_f9fbcbf79715244c7ff909d8663d782e" InResponseTo="_4b4c72d0-eb5a-0131-0fec-0050568312b8" IssueInstant="2014-07-11T18:53:30.916Z" Version="2.0"><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status><saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_fddb13c899036a90f920ddaac50fc0d6" IssueInstant="2014-07-11T18:53:30.916Z" Version="2.0"><saml:Issuer>https://hw6dldc.vmwdemo.com/SAAS/API/1.0/GET/metadata/idp.xml</saml:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
2
+ <ds:SignedInfo>
3
+ <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
4
+ <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
5
+ <ds:Reference URI="#_fddb13c899036a90f920ddaac50fc0d6">
6
+ <ds:Transforms>
7
+ <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
8
+ <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="ds saml xenc xs xsi"/></ds:Transform>
9
+ </ds:Transforms>
10
+ <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
11
+ <ds:DigestValue>HS49Xqi+JftXvslmp/boT9ixzp8=</ds:DigestValue>
12
+ </ds:Reference>
13
+ </ds:SignedInfo>
14
+ <ds:SignatureValue>
15
+ gdY9y3GNOgOqBOlEx981yILKAssUG79fXw639MJB3uJjLYokqY+Y5KFFtAU4FGvh/L6Romghx0is
16
+ rxukFkfw9coxKOhCoDZiaYPvvuC2qqhTwTAZ0Spvwuffrj3UwztSWbS6JGXtebo4ghKnae4hH5lF
17
+ tRawV9HnbLJmhL3cVPSu+7SF3iWov0PZyZczH1P6sZrYeX5X32h3RhXXxMi3kgHGWxaVTQmgTEgu
18
+ xN3GD7lnsf+WOAvdPAPgFrJjEGJZDd/MClS/x5ZwLnMZ82r7XHoFhiC47eq3Te+JE9qZvSbIs/om
19
+ dpuFSaFKxxdM8C+vHTRUDDaGckqckPc5Y7wlgA==
20
+ </ds:SignatureValue>
21
+ </ds:Signature><saml:Subject><saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" NameQualifier="https://hw6dldc.vmwdemo.com/SAAS/API/1.0/GET/metadata/idp.xml">akjoshi87+du@gmail.com</saml:NameID><saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml:SubjectConfirmationData InResponseTo="_4b4c72d0-eb5a-0131-0fec-0050568312b8" NotOnOrAfter="2014-07-11T18:56:50.916Z" Recipient="https://vmwdemo.socialcast.com/saml/authenticate"/></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore="2014-07-11T18:53:15.916Z" NotOnOrAfter="2014-07-11T18:56:50.916Z"><saml:AudienceRestriction><saml:Audience>vmwdemo.socialcast.com</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant="2014-07-11T18:53:30.916Z" SessionIndex="_876ca8142c7ba8126af3c90d952af251"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name="first_name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Demo</saml:AttributeValue></saml:Attribute><saml:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">akjoshi87+du@gmail.com</saml:AttributeValue></saml:Attribute><saml:Attribute Name="last_name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">User</saml:AttributeValue></saml:Attribute><saml:EncryptedAttribute><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_2a1c0500932ae79e9f5ede82dccb57c6" Type="http://www.w3.org/2001/04/xmlenc#Element"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><xenc:EncryptedKey Id="_ff2d29836cd453cdfca94b69b630cf40"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/><xenc:CipherData><xenc:CipherValue>IdFfvxdt+YBaLSkWfcxuGqiPDyiQtpklGkJZFW+UoZXMhopZXmW/ekfEAf1VpzIlDlo3xwY2y8Rw
22
+ zZwASwjiuHoQSMZQzZ6Ws184f1pWh9un23wgHzYc/jwXF0pXfcVL944SSxxNO4zO+DMJz6Px9rvk
23
+ Rpac86uujfBuqXlo684=</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></ds:KeyInfo><xenc:CipherData><xenc:CipherValue>/+Noi1tNN1HcY+bW/iyBkwOYR4X32pTPzq7EjQO/HB3L0B2RtpsYkvC9750eb6KydbsBSGCyNt3k
24
+ grjcI1nUgvvY488NhIo9+PWv3MhAqnljKhDzl6AcfE00Lq3HA1FcTCwrE0VLjUV4NtztK2JVCZwu
25
+ ToViUJMlu1SGL8U7uRfsRpbrXoIEv1AwFHjz+XZgwD3nxl79iAcnm3FFX7nIkjUQIPPBWC/U4XJN
26
+ u+u5svSoUpIOFqdeNcDQUq5+P5lXT46O5LcULQrEY8xHNGToxOwINMOrU+rCgwyAVbP/SaY9ywYe
27
+ bxpESNkHmkjLAI7GBvLRRkTEE88Q6/uV9D1A5X3rT4BMQJ0N7BfgnOJ7IMga2Q9wU9oPuoCsqL9I
28
+ bP9IY1vCLcAAEsMR0EgZaInLCiLoXdmDHllSo2fyKQqBGxE+KpZhvVdCOVzLN3+TrW3k/xl/kx6w
29
+ AIPFlXd6TRVzmg==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></saml:EncryptedAttribute></saml:AttributeStatement></saml:Assertion></samlp:Response>
@@ -64,4 +64,4 @@
64
64
  </saml:Attribute>
65
65
  </saml:AttributeStatement>
66
66
  </saml:Assertion>
67
- </samlp:Response>
67
+ </samlp:Response>
@@ -0,0 +1,4 @@
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,18 +1,23 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class SettingsTest < Minitest::Test
3
+ class SettingsTest < Test::Unit::TestCase
4
4
 
5
- describe "Settings" do
6
- before do
5
+ context "Settings" do
6
+ setup do
7
7
  @settings = OneLogin::RubySaml::Settings.new
8
8
  end
9
- it "should provide getters and settings" do
9
+ should "should provide getters and settings" do
10
10
  accessors = [
11
- :assertion_consumer_service_url, :issuer, :sp_entity_id, :sp_name_qualifier,
12
- :idp_sso_target_url, :idp_cert_fingerprint, :name_identifier_format,
13
- :idp_slo_target_url, :name_identifier_value, :name_identifier_value_requested,
14
- :sessionindex, :assertion_consumer_logout_service_url,
15
- :passive, :force_authn, :protocol_binding, :single_logout_service_url, :single_logout_service_binding
11
+ :idp_entity_id, :idp_sso_target_url, :idp_slo_target_url, :idp_cert, :idp_cert_fingerprint,
12
+ :issuer, :assertion_consumer_service_url, :assertion_consumer_service_binding,
13
+ :single_logout_service_url, :single_logout_service_binding,
14
+ :sp_name_qualifier, :name_identifier_format, :name_identifier_value,
15
+ :sessionindex, :attributes_index, :passive, :force_authn,
16
+ :compress_request, :double_quote_xml_attribute_values, :protocol_binding,
17
+ :security, :certificate, :private_key,
18
+ :authn_context, :authn_context_comparison, :authn_context_decl_ref,
19
+ :assertion_consumer_logout_service_url,
20
+ :assertion_consumer_logout_service_binding
16
21
  ]
17
22
 
18
23
  accessors.each do |accessor|
@@ -20,9 +25,10 @@ class SettingsTest < Minitest::Test
20
25
  @settings.send("#{accessor}=".to_sym, value)
21
26
  assert_equal value, @settings.send(accessor)
22
27
  end
28
+
23
29
  end
24
30
 
25
- it "create settings from hash" do
31
+ should "create settings from hash" do
26
32
 
27
33
  config = {
28
34
  :assertion_consumer_service_url => "http://app.muda.no/sso",
@@ -32,6 +38,7 @@ class SettingsTest < Minitest::Test
32
38
  :idp_slo_target_url => "http://sso.muda.no/slo",
33
39
  :idp_cert_fingerprint => "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
34
40
  :name_identifier_format => "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
41
+ :attributes_index => 30,
35
42
  :passive => true,
36
43
  :protocol_binding => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
37
44
  }
@@ -42,110 +49,16 @@ class SettingsTest < Minitest::Test
42
49
  end
43
50
  end
44
51
 
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
52
+ should "configure attribute service attributes correctly" do
53
+ @settings = OneLogin::RubySaml::Settings.new
54
+ @settings.attribute_consuming_service.configure do
55
+ service_name "Test Service"
56
+ add_attribute :name => "Name", :name_format => "Name Format", :friendly_name => "Friendly Name"
141
57
  end
142
58
 
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
59
+ assert_equal @settings.attribute_consuming_service.configured?, true
60
+ assert_equal @settings.attribute_consuming_service.name, "Test Service"
61
+ assert_equal @settings.attribute_consuming_service.attributes, [{:name => "Name", :name_format => "Name Format", :friendly_name => "Friendly Name" }]
149
62
  end
150
63
 
151
64
  end
@@ -1,64 +1,61 @@
1
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"))
2
+ require 'responses/logoutresponse_fixtures'
3
3
 
4
- class SloLogoutrequestTest < Minitest::Test
4
+ class RubySamlTest < Test::Unit::TestCase
5
5
 
6
- describe "SloLogoutrequest" do
6
+ context "SloLogoutrequest" do
7
+ should "raise an exception when response is initialized with nil" do
8
+ assert_raises(ArgumentError) { OneLogin::RubySaml::SloLogoutrequest.new(nil) }
9
+ end
7
10
 
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
+ context "#is_valid?" do
12
+ should "return false when response is initialized with blank data" do
13
+ request = OneLogin::RubySaml::SloLogoutrequest.new('')
14
+ assert !request.is_valid?
11
15
  end
12
- it "default to empty settings" do
13
- logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request)
14
- assert logoutrequest.settings.nil?
16
+
17
+ should "return true when the request is initialized with valid data" do
18
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
19
+ assert request.is_valid?
20
+ assert_equal 'someone@example.org', request.name_id
15
21
  end
16
- it "accept constructor-injected settings" do
17
- logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request, settings)
18
- assert !logoutrequest.settings.nil?
22
+
23
+ should "should be idempotent when the response is initialized with invalid data" do
24
+ request = OneLogin::RubySaml::SloLogoutrequest.new(invalid_xml_response)
25
+ assert !request.is_valid?
26
+ assert !request.is_valid?
19
27
  end
20
- it "accept constructor-injected options" do
21
- logoutrequest = OneLogin::RubySaml::SloLogoutrequest.new(valid_request, nil, { :foo => :bar} )
22
- assert !logoutrequest.options.empty?
28
+
29
+ should "should be idempotent when the response is initialized with valid data" do
30
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
31
+ assert request.is_valid?
32
+ assert request.is_valid?
23
33
  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
34
 
28
- assert_equal expected_request, logoutrequest.request
35
+ should "raise error for invalid xml" do
36
+ logout_request = OneLogin::RubySaml::SloLogoutrequest.new(invalid_xml_response)
37
+ assert_raises(OneLogin::RubySaml::ValidationError) { logout_request.validate! }
29
38
  end
30
39
  end
31
40
 
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
41
+ context "#name_id" do
42
+ should "extract the value of the name id element" do
43
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
44
+ assert_equal "someone@example.org", request.name_id
45
45
  end
46
-
47
46
  end
48
47
 
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!
48
+ context "#issuer" do
49
+ should "return the issuer inside the request" do
50
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
51
+ assert_equal "https://app.onelogin.com/saml/metadata/SOMEACCOUNT", request.issuer
56
52
  end
53
+ end
57
54
 
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! }
55
+ context "#id" do
56
+ should "extract the value of the ID attribute" do
57
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
58
+ assert_equal "_c0348950-935b-0131-1060-782bcb56fcaa", request.id
62
59
  end
63
60
  end
64
61
 
@@ -1,226 +1,146 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
2
2
 
3
- class SloLogoutresponseTest < Minitest::Test
3
+ class SloLogoutresponseTest < Test::Unit::TestCase
4
4
 
5
- describe "SloLogoutresponse" do
5
+ context "SloLogoutresponse" do
6
+ settings = OneLogin::RubySaml::Settings.new
6
7
 
7
- let(:settings) { OneLogin::RubySaml::Settings.new }
8
-
9
- before do
8
+ should "create the deflated SAMLResponse URL parameter" do
10
9
  settings.idp_slo_target_url = "http://unauth.com/logout"
11
10
  settings.name_identifier_value = "f00f00"
12
11
  settings.compress_request = true
13
- settings.certificate = ruby_saml_cert_text
14
- settings.private_key = ruby_saml_key_text
15
- end
16
12
 
17
- it "create the deflated SAMLResponse URL parameter" do
18
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings)
19
- assert_match /^http:\/\/unauth\.com\/logout\?SAMLResponse=/, unauth_url
13
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
20
14
 
21
- inflated = decode_saml_response_payload(unauth_url)
22
- assert_match /^<samlp:LogoutResponse/, inflated
23
- end
15
+ assert request.is_valid?
24
16
 
25
- it "support additional params" do
26
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { :hello => nil })
27
- assert_match /&hello=$/, unauth_url
17
+ unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, request.id)
18
+ assert unauth_url =~ /^http:\/\/unauth\.com\/logout\?SAMLResponse=/
28
19
 
29
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { :foo => "bar" })
30
- assert_match /&foo=bar$/, unauth_url
20
+ inflated = decode_saml_response_payload(unauth_url)
31
21
 
32
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { :RelayState => "http://idp.example.com" })
33
- assert_match /&RelayState=http%3A%2F%2Fidp.example.com$/, unauth_url
22
+ assert_match /^<samlp:LogoutResponse/, inflated
34
23
  end
35
24
 
36
- it "RelayState cases" do
37
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { :RelayState => nil })
38
- assert !unauth_url.include?('RelayState')
25
+ should "support additional params" do
26
+ settings.idp_slo_target_url = "http://unauth.com/logout"
27
+ settings.name_identifier_value = "f00f00"
28
+ settings.compress_request = true
29
+
30
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
39
31
 
40
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { :RelayState => "http://example.com" })
41
- assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
32
+ unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, request.id, nil, { :hello => nil })
33
+ assert unauth_url =~ /&hello=$/
42
34
 
43
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { 'RelayState' => nil })
44
- assert !unauth_url.include?('RelayState')
35
+ unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, request.id, nil, { :foo => "bar" })
36
+ assert unauth_url =~ /&foo=bar$/
45
37
 
46
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, nil, { 'RelayState' => "http://example.com" })
47
- assert unauth_url.include?('&RelayState=http%3A%2F%2Fexample.com')
38
+ unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, request.id, nil, { :RelayState => "http://idp.example.com" })
39
+ assert unauth_url =~ /&RelayState=http%3A%2F%2Fidp.example.com$/
48
40
  end
49
41
 
50
- it "set InResponseTo to the ID from the logout request" do
51
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, '_c0348950-935b-0131-1060-782bcb56fcaa')
42
+ should "set InResponseTo to the ID from the logout request" do
43
+ settings.idp_slo_target_url = "http://unauth.com/logout"
44
+ settings.name_identifier_value = "f00f00"
45
+ settings.compress_request = true
46
+
47
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
48
+ unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, request.id)
52
49
 
53
50
  inflated = decode_saml_response_payload(unauth_url)
51
+
54
52
  assert_match /InResponseTo='_c0348950-935b-0131-1060-782bcb56fcaa'/, inflated
55
53
  end
56
54
 
57
- it "set a custom successful logout message on the response" do
58
- unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, nil, "Custom Logout Message")
55
+ should "set a custom successful logout message on the response" do
56
+ settings.idp_slo_target_url = "http://unauth.com/logout"
57
+ settings.name_identifier_value = "f00f00"
58
+ settings.compress_request = true
59
+
60
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
61
+ unauth_url = OneLogin::RubySaml::SloLogoutresponse.new.create(settings, request.id, "Custom Logout Message")
59
62
 
60
63
  inflated = decode_saml_response_payload(unauth_url)
64
+
61
65
  assert_match /<samlp:StatusMessage>Custom Logout Message<\/samlp:StatusMessage>/, inflated
62
66
  end
63
67
 
64
- describe "when the settings indicate to sign (embedded) logout response" do
65
-
66
- before do
68
+ context "when the settings indicate to sign (embebed) the logout response" do
69
+ should "create a signed logout response" do
70
+ settings = OneLogin::RubySaml::Settings.new
67
71
  settings.compress_response = false
72
+ settings.idp_slo_target_url = "http://example.com?field=value"
68
73
  settings.security[:logout_responses_signed] = true
69
74
  settings.security[:embed_sign] = true
70
- end
71
-
72
- it "doesn't sign through create_xml_document" do
73
- unauth_res = OneLogin::RubySaml::SloLogoutresponse.new
74
- inflated = unauth_res.create_xml_document(settings).to_s
75
-
76
- refute_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
77
- refute_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
78
- refute_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
79
- end
80
-
81
- it "sign unsigned request" do
82
- unauth_res = OneLogin::RubySaml::SloLogoutresponse.new
83
- unauth_res_doc = unauth_res.create_xml_document(settings)
84
- inflated = unauth_res_doc.to_s
75
+ settings.certificate = ruby_saml_cert_text
76
+ settings.private_key = ruby_saml_key_text
85
77
 
86
- refute_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
87
- refute_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
88
- refute_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
89
-
90
- inflated = unauth_res.sign_document(unauth_res_doc, settings).to_s
91
-
92
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
93
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
94
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
95
- end
96
-
97
- it "signs through create_logout_response_xml_doc" do
98
- unauth_res = OneLogin::RubySaml::SloLogoutresponse.new
99
- inflated = unauth_res.create_logout_response_xml_doc(settings).to_s
100
-
101
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], inflated
102
- assert_match %r[<ds:SignatureMethod Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1'/>], inflated
103
- assert_match %r[<ds:DigestMethod Algorithm='http://www.w3.org/2000/09/xmldsig#sha1'/>], inflated
104
- end
105
-
106
- it "create a signed logout response" do
107
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message")
78
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
79
+ params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, request.id, "Custom Logout Message")
108
80
 
109
81
  response_xml = Base64.decode64(params["SAMLResponse"])
110
82
  assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], response_xml
111
- assert_match /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig#rsa-sha1'\/>/, response_xml
112
- assert_match /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig#sha1'\/>/, response_xml
83
+ response_xml =~ /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig#rsa-sha1'\/>/
84
+ response_xml =~ /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2000\/09\/xmldsig#rsa-sha1'\/>/
113
85
  end
114
86
 
115
- it "create a signed logout response with 256 digest and signature methods" do
116
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
117
- settings.security[:digest_method] = XMLSecurity::Document::SHA256
118
-
119
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message")
120
-
121
- response_xml = Base64.decode64(params["SAMLResponse"])
122
- assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], response_xml
123
- assert_match /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmldsig-more#rsa-sha256'\/>/, response_xml
124
- assert_match /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmlenc#sha256'\/>/, response_xml
125
- end
126
-
127
- it "create a signed logout response with 512 digest and signature method RSA_SHA384" do
128
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
87
+ should "create a signed logout response with 256 digest and signature methods" do
88
+ settings = OneLogin::RubySaml::Settings.new
89
+ settings.compress_response = false
90
+ settings.idp_slo_target_url = "http://example.com?field=value"
91
+ settings.security[:logout_responses_signed] = true
92
+ settings.security[:embed_sign] = true
93
+ settings.security[:signature_method] = XMLSecurity::Document::SHA256
129
94
  settings.security[:digest_method] = XMLSecurity::Document::SHA512
95
+ settings.certificate = ruby_saml_cert_text
96
+ settings.private_key = ruby_saml_key_text
130
97
 
131
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message")
98
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
99
+ params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, request.id, "Custom Logout Message")
132
100
 
133
101
  response_xml = Base64.decode64(params["SAMLResponse"])
134
102
  assert_match %r[<ds:SignatureValue>([a-zA-Z0-9/+=]+)</ds:SignatureValue>], response_xml
135
- assert_match /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmldsig-more#rsa-sha384'\/>/, response_xml
136
- assert_match /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmlenc#sha512'\/>/, response_xml
103
+ response_xml =~ /<ds:SignatureMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmldsig-more#rsa-sha256'\/>/
104
+ response_xml =~ /<ds:DigestMethod Algorithm='http:\/\/www.w3.org\/2001\/04\/xmldsig-more#rsa-sha512'\/>/
137
105
  end
138
106
  end
139
107
 
140
- describe "#create_params when the settings indicate to sign the logout response" do
141
-
142
- let(:cert) { OpenSSL::X509::Certificate.new(ruby_saml_cert_text) }
143
-
144
- before do
108
+ context "when the settings indicate to sign the logout response" do
109
+ should "create a signature parameter" do
110
+ settings = OneLogin::RubySaml::Settings.new
145
111
  settings.compress_response = false
112
+ settings.idp_slo_target_url = "http://example.com?field=value"
113
+ settings.assertion_consumer_service_binding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
146
114
  settings.security[:logout_responses_signed] = true
147
115
  settings.security[:embed_sign] = false
148
- end
149
-
150
- it "create a signature parameter with RSA_SHA1 and validate it" do
151
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA1
152
-
153
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message", :RelayState => 'http://example.com')
154
- assert params['SAMLResponse']
155
- assert params[:RelayState]
156
- assert params['Signature']
157
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA1
158
-
159
- query_string = "SAMLResponse=#{CGI.escape(params['SAMLResponse'])}"
160
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
161
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
162
-
163
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
164
- assert_equal signature_algorithm, OpenSSL::Digest::SHA1
165
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
166
- end
116
+ settings.security[:signature_method] = XMLSecurity::Document::SHA1
117
+ settings.certificate = ruby_saml_cert_text
118
+ settings.private_key = ruby_saml_key_text
167
119
 
168
- it "create a signature parameter with RSA_SHA256 /SHA256 and validate it" do
169
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
170
-
171
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message", :RelayState => 'http://example.com')
172
- assert params['SAMLResponse']
173
- assert params[:RelayState]
120
+ request = OneLogin::RubySaml::SloLogoutrequest.new(logout_request_document)
121
+ params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, request.id, "Custom Logout Message")
174
122
  assert params['Signature']
123
+ assert params['SigAlg'] == XMLSecurity::Document::SHA1
175
124
 
176
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA256
177
-
178
- query_string = "SAMLResponse=#{CGI.escape(params['SAMLResponse'])}"
179
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
180
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
181
-
182
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
183
- assert_equal signature_algorithm, OpenSSL::Digest::SHA256
184
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
185
- end
186
-
187
- it "create a signature parameter with RSA_SHA384 / SHA384 and validate it" do
188
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA384
189
-
190
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message", :RelayState => 'http://example.com')
191
- assert params['SAMLResponse']
192
- assert params[:RelayState]
125
+ # signature_method only affects the embedeed signature
126
+ settings.security[:signature_method] = XMLSecurity::Document::SHA256
127
+ params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, request.id, "Custom Logout Message")
193
128
  assert params['Signature']
194
-
195
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA384
196
-
197
- query_string = "SAMLResponse=#{CGI.escape(params['SAMLResponse'])}"
198
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
199
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
200
-
201
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
202
- assert_equal signature_algorithm, OpenSSL::Digest::SHA384
203
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
129
+ assert params['SigAlg'] == XMLSecurity::Document::SHA1
204
130
  end
131
+ end
205
132
 
206
- it "create a signature parameter with RSA_SHA512 / SHA512 and validate it" do
207
- settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA512
208
-
209
- params = OneLogin::RubySaml::SloLogoutresponse.new.create_params(settings, nil, "Custom Logout Message", :RelayState => 'http://example.com')
210
- assert params['SAMLResponse']
211
- assert params[:RelayState]
212
- assert params['Signature']
213
-
214
- assert_equal params['SigAlg'], XMLSecurity::Document::RSA_SHA512
133
+ end
215
134
 
216
- query_string = "SAMLResponse=#{CGI.escape(params['SAMLResponse'])}"
217
- query_string << "&RelayState=#{CGI.escape(params[:RelayState])}"
218
- query_string << "&SigAlg=#{CGI.escape(params['SigAlg'])}"
135
+ def decode_saml_response_payload(unauth_url)
136
+ payload = CGI.unescape(unauth_url.split("SAMLResponse=").last)
137
+ decoded = Base64.decode64(payload)
219
138
 
220
- signature_algorithm = XMLSecurity::BaseDocument.new.algorithm(params['SigAlg'])
221
- assert_equal signature_algorithm, OpenSSL::Digest::SHA512
222
- assert cert.public_key.verify(signature_algorithm.new, Base64.decode64(params['Signature']), query_string)
223
- end
224
- end
139
+ zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS)
140
+ inflated = zstream.inflate(decoded)
141
+ zstream.finish
142
+ zstream.close
143
+ inflated
225
144
  end
145
+
226
146
  end