title: How do I correctly prepare an 'HTTP Redirect Binding' SAML Request using C#
body: <p>I need to create an SP initiated SAML 2.0 Authentication transaction using HTTP Redirect Binding method. It turns out this is quite easy. Just get the IdP URI and concatenate a single query-string param  <code>SAMLRequest</code>. The param is an encoded block of xml that describes the SAML request. So far so good.</p>
  
  <p>The problem comes when converting the SAML into the query string param. I believe this process of preparation should be:</p>
  
  <ol>
  <li>Build a SAML string</li>
  <li>Compress this string</li>
  <li>Base64 encode the string</li>
  <li>UrlEncode the string.</li>
  </ol>
  
  <p><strong>The SAML Request</strong></p>
  
  <pre><code>&lt;samlp:AuthnRequest
      xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
      xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
      ID="{0}"
      Version="2.0"
      AssertionConsumerServiceIndex="0"
      AttributeConsumingServiceIndex="0"&gt;
      &lt;saml:Issuer&gt;URN:xx-xx-xx&lt;/saml:Issuer&gt;
      &lt;samlp:NameIDPolicy
          AllowCreate="true"
          Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/&gt;
  &lt;/samlp:AuthnRequest&gt;
  </code></pre>
  
  <p><strong>The Code</strong></p>
  
  <pre><code>private string GetSAMLHttpRedirectUri(string idpUri)
  {
      var saml = string.Format(SAMLRequest, Guid.NewGuid());
      var bytes = Encoding.UTF8.GetBytes(saml);
      using (var output = new MemoryStream())
      {
          using (var zip = new DeflaterOutputStream(output))
          {
              zip.Write(bytes, 0, bytes.Length);
          }
          var base64 = Convert.ToBase64String(output.ToArray());
          var urlEncode = HttpUtility.UrlEncode(base64);
          return string.Concat(idpUri, "?SAMLRequest=", urlEncode);
      }
  }
  </code></pre>
  
  <p>I suspect the compression is somehow to blame. I am using the <code>DeflaterOutputStream</code> class from <a href="http://www.icsharpcode.net/opensource/sharpziplib/" rel="noreferrer">SharpZipLib</a> which is supposed to implement an industry standard deflate-algorithm so perhaps there are some settings here I have wrong?</p>
  
  <p>The encoded output can be tested using this <a href="https://rnd.feide.no/simplesaml/module.php/saml2debug/debug.php" rel="noreferrer">SAML2.0 Debugger</a> (its a useful online conversion tool). When I decode my output using this tool it comes out as nonsense.</p>
  
  <p>The question therefore is: Do you know how to convert a SAML string into the correctly deflated and encoded SAMLRequest query-param?</p>
  
  <p>Thank you</p>
  
  <p><strong>EDIT 1</strong></p>
  
  <p>The accepted answer below gives the answer to the problem. Here is final code as corrected by all subsequent comments and answers.</p>
  
  <p><strong>Encode SAMLRequest - Working Code</strong></p>
  
  <pre><code>private string GenerateSAMLRequestParam()
  {
      var saml = string.Format(SAMLRequest, Guid.NewGuid());
      var bytes = Encoding.UTF8.GetBytes(saml);
      using (var output = new MemoryStream())
      {
          using (var zip = new DeflateStream(output, CompressionMode.Compress))
          {
              zip.Write(bytes, 0, bytes.Length);
          }
          var base64 = Convert.ToBase64String(output.ToArray());
          return HttpUtility.UrlEncode(base64);
      }
  }
  </code></pre>
  
  <p>The <code>SAMLRequest</code> variable contains the SAML shown at the top of this question. </p>
  
  <p><strong>Decode SAMLResponse - Working Code</strong></p>
  
  <pre><code>private string DecodeSAMLResponse(string response)
  {
      var utf8 = Encoding.UTF8;
      var bytes = utf8.GetBytes(response);
      using (var output = new MemoryStream())
      {
          using (new DeflateStream(output, CompressionMode.Decompress))
          {
              output.Write(bytes, 0, bytes.Length);
          }
          var base64 = utf8.GetString(output.ToArray());
          return utf8.GetString(Convert.FromBase64String(base64));
      }
  }
  </code></pre>