{"id":19,"date":"2013-02-07T11:03:18","date_gmt":"2013-02-07T11:03:18","guid":{"rendered":"http:\/\/blogs.kent.ac.uk\/unseenit\/?p=19"},"modified":"2016-07-08T10:42:47","modified_gmt":"2016-07-08T09:42:47","slug":"simple-shibboleth-ecp-test","status":"publish","type":"post","link":"https:\/\/blogs.kent.ac.uk\/unseenit\/simple-shibboleth-ecp-test\/","title":{"rendered":"Simple Shibboleth ECP test"},"content":{"rendered":"<p><strong>Update: I&#8217;ve published an even easier way to test ECP on GitHub at\u00a0<a href=\"https:\/\/github.com\/unikent-ms1\/simple-soap-ecp-test\">https:\/\/github.com\/unikent-ms1\/simple-soap-ecp-test<\/a><\/strong><\/p>\n<p><a href=\"http:\/\/shibboleth.net\/\">Shibboleth<\/a> (well, SAML2 via Shibboleth) provides a mechanism for non-browser clients to go through an Authentication\/Authorisation (AuthNZ) directly with a Service Provider (SP) by making a SOAP callback to a trusted Identity Provider (IdP) on behalf of the client. This mechanism is called <a href=\"https:\/\/wiki.shibboleth.net\/confluence\/display\/SHIB2\/ECP\">Enhanced Client or Proxy<\/a> (ECP).<\/p>\n<p>While attempting to get this enabled and working, it became apparent that there is very little in the way of test-rigs for this mechanism\u2026 so I came up with a simple (bodgy) method and then, later, wrote a JMeter rig to test it more extensively.<\/p>\n<p><strong>Note: the method described here only covers the &#8220;Basic Auth&#8221; method of using ECP. There are others of which I have, thus far, no experience.<\/strong><\/p>\n<p>At a very basic level, an ECP callback is just an HTTP SOAP request with some HTTP Basic Auth credentials included. I crafted a SAML2 AuthN request, wrapped it in the appropriate SOAP glue and sent it to the web server hosting the ECP endpoint using <code style=\"font-style: inherit\">curl<\/code>.<\/p>\n<p>Save the below XML document to a text file and replace the bits marked with double-underscores as follows:<\/p>\n<ul>\n<li><span style=\"line-height: 15px\"><code>__RANDOM_STRING__<\/code>: This can be literally anything so long as it&#8217;s unique between requests. I started off with an MD5 of a file and manually incremented the last character each time I used it<\/span><\/li>\n<li><code>__AssertionConsumerServiceURL__<\/code>: This is the URL specified in the metadata of the SP you&#8217;re impersonating for the\u00a0<code>AssertionConsumerService<\/code> attribute with binding <code>urn:oasis:names:tc:SAML:2.0:bindings:PAOS<\/code><\/li>\n<li><code>IssueInstant<\/code>: This is the current time. It&#8217;s up to the IdP to check this but set it to something within a few minutes of\u00a0<em>now<\/em> in the format I&#8217;ve used and it should be ok. Just remember to keep it close to now :)If using JMeter then <a href=\"mailto:crt@ufl.edu\">Charles Tompkins<\/a> of University of Florida suggests using the following macro:\n<pre>${__javaScript(var z=new Date(); $DATE=z.toISOString();,DATE)}<\/pre>\n<\/li>\n<li><code>__REMOTE_ENTITYID__<\/code>: This is the EntityID of the SP you&#8217;re impersonating<\/li>\n<\/ul>\n<pre>&lt;SOAP-ENV:Envelope \r\n    xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"\r\n    xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" \r\n    xmlns:SOAP-ENV=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\"\r\n    xmlns:ecp=\"urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp\"&gt;\r\n    &lt;SOAP-ENV:Header&gt;\r\n     &lt;\/SOAP-ENV:Header&gt;\r\n     &lt;SOAP-ENV:Body&gt; \r\n        &lt;samlp:AuthnRequest\r\n\t\tID=\"__RANDOM_STRING__\" \r\n\t\tProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:PAOS\"\r\n\t\tAssertionConsumerServiceURL=\"__AssertionConsumerServiceURL__\"\r\n\t\tIssueInstant=\"__2013-01-01T00:00:00Z__\"\r\n\t\tVersion=\"2.0\"\r\n\t&gt;\r\n\t&lt;saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\"&gt;\r\n\t\t__REMOTE_ENTITYID__\r\n\t&lt;\/saml:Issuer&gt;\r\n\t&lt;samlp:NameIDPolicy AllowCreate=\"1\"\/&gt;\r\n\t&lt;\/samlp:AuthnRequest&gt;       \r\n     &lt;\/SOAP-ENV:Body&gt; \r\n&lt;\/SOAP-ENV:Envelope&gt;<\/pre>\n<p>Save that as something like <code>soap.xml<\/code> and proceed to <code>curl<\/code>\u2026<\/p>\n<p>Invoking curl in such a way that this works takes a little effort:<\/p>\n<pre>curl -k \\\r\n  -d @soap.xml \\\r\n  -H \"Content-Type: application\/vnd.paos+xml\" \\\r\n  --basic -u user:password \\\r\n  https:\/\/idp.example.com\/idp\/profile\/SAML2\/SOAP\/ECP \\\r\n  | xmllint --pretty 1 -<\/pre>\n<p>If you&#8217;ve got the URL and credentials correct then should get some sort of XML response back (I&#8217;ve found that it&#8217;s a lot more readable if you pass it through xmllint to pretify it). Hopefully this will be a Response object but may be an error.<\/p>\n<p>You can add &#8220;<code>--trace-ascii -<\/code>&#8221; to the curl command to get a more verbose output of what&#8217;s going on.<\/p>\n<p>Remember to change the ID attribute each time you use it and keep an eye on the IssueInstant \u2013 if it&#8217;s more than a few minutes off then it&#8217;ll probably get rejected.<\/p>\n<p>For more information about the guts of ECP (and SAML2 more generally) see the <a href=\"https:\/\/www.oasis-open.org\/committees\/download.php\/27819\/sstc-saml-tech-overview-2.0-cd-02.pdf\">specification<\/a>&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Update: I&#8217;ve published an even easier way to test ECP on GitHub at\u00a0https:\/\/github.com\/unikent-ms1\/simple-soap-ecp-test Shibboleth (well, SAML2 via Shibboleth) provides a mechanism for non-browser clients to &hellip; <a href=\"https:\/\/blogs.kent.ac.uk\/unseenit\/simple-shibboleth-ecp-test\/\">Read&nbsp;more<\/a><\/p>\n","protected":false},"author":13,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[28933],"tags":[28925,863,119,28927],"_links":{"self":[{"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/posts\/19"}],"collection":[{"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/comments?post=19"}],"version-history":[{"count":14,"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/posts\/19\/revisions"}],"predecessor-version":[{"id":374,"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/posts\/19\/revisions\/374"}],"wp:attachment":[{"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/media?parent=19"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/categories?post=19"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.kent.ac.uk\/unseenit\/wp-json\/wp\/v2\/tags?post=19"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}