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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +1 -6
- data/Gemfile +2 -12
- data/README.md +363 -35
- data/Rakefile +14 -0
- data/changelog.md +22 -9
- data/lib/onelogin/ruby-saml/attribute_service.rb +34 -0
- data/lib/onelogin/ruby-saml/attributes.rb +26 -64
- data/lib/onelogin/ruby-saml/authrequest.rb +47 -89
- data/lib/onelogin/ruby-saml/idp_metadata_parser.rb +87 -0
- data/lib/onelogin/ruby-saml/logoutrequest.rb +34 -93
- data/lib/onelogin/ruby-saml/logoutresponse.rb +25 -24
- data/lib/onelogin/ruby-saml/metadata.rb +46 -16
- data/lib/onelogin/ruby-saml/response.rb +62 -322
- data/lib/onelogin/ruby-saml/saml_message.rb +78 -0
- data/lib/onelogin/ruby-saml/settings.rb +54 -121
- data/lib/onelogin/ruby-saml/slo_logoutrequest.rb +26 -61
- data/lib/onelogin/ruby-saml/slo_logoutresponse.rb +27 -84
- data/lib/onelogin/ruby-saml/utils.rb +32 -199
- data/lib/onelogin/ruby-saml/version.rb +1 -1
- data/lib/ruby-saml.rb +5 -2
- data/lib/schemas/{saml20assertion_schema.xsd → saml-schema-assertion-2.0.xsd} +283 -283
- data/lib/schemas/saml-schema-authn-context-2.0.xsd +23 -0
- data/lib/schemas/saml-schema-authn-context-types-2.0.xsd +821 -0
- data/lib/schemas/saml-schema-metadata-2.0.xsd +339 -0
- data/lib/schemas/{saml20protocol_schema.xsd → saml-schema-protocol-2.0.xsd} +302 -302
- data/lib/schemas/sstc-metadata-attr.xsd +35 -0
- data/lib/schemas/sstc-saml-attribute-ext.xsd +25 -0
- data/lib/schemas/sstc-saml-metadata-algsupport-v1.0.xsd +41 -0
- data/lib/schemas/sstc-saml-metadata-ui-v1.0.xsd +89 -0
- data/lib/schemas/{xenc_schema.xsd → xenc-schema.xsd} +1 -11
- data/lib/schemas/xml.xsd +287 -0
- data/lib/schemas/{xmldsig_schema.xsd → xmldsig-core-schema.xsd} +0 -9
- data/lib/xml_security.rb +83 -235
- data/ruby-saml.gemspec +1 -0
- data/test/idp_metadata_parser_test.rb +54 -0
- data/test/logoutrequest_test.rb +68 -144
- data/test/logoutresponse_test.rb +43 -25
- data/test/metadata_test.rb +87 -0
- data/test/request_test.rb +103 -90
- data/test/response_test.rb +181 -471
- data/test/responses/idp_descriptor.xml +3 -0
- data/test/responses/logoutresponse_fixtures.rb +5 -5
- data/test/responses/response_no_cert_and_encrypted_attrs.xml +29 -0
- data/test/responses/response_with_multiple_attribute_values.xml +1 -1
- data/test/responses/slo_request.xml +4 -0
- data/test/settings_test.rb +25 -112
- data/test/slo_logoutrequest_test.rb +41 -44
- data/test/slo_logoutresponse_test.rb +87 -167
- data/test/test_helper.rb +27 -102
- data/test/xml_security_test.rb +114 -337
- metadata +34 -84
- data/lib/onelogin/ruby-saml/setting_error.rb +0 -6
- data/test/certificates/certificate.der +0 -0
- data/test/certificates/formatted_certificate +0 -14
- data/test/certificates/formatted_chained_certificate +0 -42
- data/test/certificates/formatted_private_key +0 -12
- data/test/certificates/formatted_rsa_private_key +0 -12
- data/test/certificates/invalid_certificate1 +0 -1
- data/test/certificates/invalid_certificate2 +0 -1
- data/test/certificates/invalid_certificate3 +0 -12
- data/test/certificates/invalid_chained_certificate1 +0 -1
- data/test/certificates/invalid_private_key1 +0 -1
- data/test/certificates/invalid_private_key2 +0 -1
- data/test/certificates/invalid_private_key3 +0 -10
- data/test/certificates/invalid_rsa_private_key1 +0 -1
- data/test/certificates/invalid_rsa_private_key2 +0 -1
- data/test/certificates/invalid_rsa_private_key3 +0 -10
- data/test/certificates/ruby-saml-2.crt +0 -15
- data/test/requests/logoutrequest_fixtures.rb +0 -47
- data/test/responses/encrypted_new_attack.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_assertion.xml.base64 +0 -1
- data/test/responses/invalids/invalid_issuer_message.xml.base64 +0 -1
- data/test/responses/invalids/multiple_signed.xml.base64 +0 -1
- data/test/responses/invalids/no_signature.xml.base64 +0 -1
- data/test/responses/invalids/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/invalids/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/invalids/signature_wrapping_attack.xml.base64 +0 -1
- data/test/responses/response_node_text_attack.xml.base64 +0 -1
- data/test/responses/response_with_concealed_signed_assertion.xml +0 -51
- data/test/responses/response_with_doubled_signed_assertion.xml +0 -49
- data/test/responses/response_with_multiple_attribute_statements.xml +0 -72
- data/test/responses/response_with_signed_assertion_3.xml +0 -30
- data/test/responses/response_with_signed_message_and_assertion.xml +0 -34
- data/test/responses/response_with_undefined_recipient.xml.base64 +0 -1
- data/test/responses/response_wrapped.xml.base64 +0 -150
- data/test/responses/valid_response.xml.base64 +0 -1
- data/test/responses/valid_response_without_x509certificate.xml.base64 +0 -1
- 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].
|
|
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].
|
|
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].
|
|
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].
|
|
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
|
-
:
|
|
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>
|
|
@@ -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>
|
data/test/settings_test.rb
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
|
2
2
|
|
|
3
|
-
class SettingsTest <
|
|
3
|
+
class SettingsTest < Test::Unit::TestCase
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
context "Settings" do
|
|
6
|
+
setup do
|
|
7
7
|
@settings = OneLogin::RubySaml::Settings.new
|
|
8
8
|
end
|
|
9
|
-
|
|
9
|
+
should "should provide getters and settings" do
|
|
10
10
|
accessors = [
|
|
11
|
-
:
|
|
12
|
-
:
|
|
13
|
-
:
|
|
14
|
-
:
|
|
15
|
-
:
|
|
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
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
2
|
+
require 'responses/logoutresponse_fixtures'
|
|
3
3
|
|
|
4
|
-
class
|
|
4
|
+
class RubySamlTest < Test::Unit::TestCase
|
|
5
5
|
|
|
6
|
-
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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 <
|
|
3
|
+
class SloLogoutresponseTest < Test::Unit::TestCase
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
context "SloLogoutresponse" do
|
|
6
|
+
settings = OneLogin::RubySaml::Settings.new
|
|
6
7
|
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
assert_match /^<samlp:LogoutResponse/, inflated
|
|
23
|
-
end
|
|
15
|
+
assert request.is_valid?
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
unauth_url
|
|
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
|
-
|
|
30
|
-
assert_match /&foo=bar$/, unauth_url
|
|
20
|
+
inflated = decode_saml_response_payload(unauth_url)
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
assert_match /&RelayState=http%3A%2F%2Fidp.example.com$/, unauth_url
|
|
22
|
+
assert_match /^<samlp:LogoutResponse/, inflated
|
|
34
23
|
end
|
|
35
24
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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,
|
|
41
|
-
assert unauth_url
|
|
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,
|
|
44
|
-
assert
|
|
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,
|
|
47
|
-
assert unauth_url
|
|
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
|
-
|
|
51
|
-
|
|
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
|
-
|
|
58
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
|
|
112
|
-
|
|
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
|
-
|
|
116
|
-
settings
|
|
117
|
-
settings.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
169
|
-
|
|
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
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|