How to get a SAML Protocol Response from ADFS using C#

ADFS (Active Directory Federation Services) is a fancy name for Windows Identity Foundation Server. ADFS supports SAML protocol, however its client, Windows Identity Foundation (WIF), does not. As most of the problems of acquiring a token can be resolved with either WS-Federation and WS-Trust, you may use WIF for your federation needs since WIF supports SAML-Token (please notice SAML-Protocol is not the same as SAML-Token).

Lately I have received requests from partners and customers to acquire a SAML Protocol Response which would require SAML-Protocol to request. WIF unfortunately cannot be used to make a SAML-Protocol request and there is no out-of-the-box way of doing that. There are some paid NuGets implementing SAML-Protocol in C#, but none is free. I put together a workaround to request a SAML-Protocol response from ADFS in C# using HttpClient (from System.Net.Http library). System.Net.Http.HttpClient class comes with .NET 4.5 and 4.5.1 and can be added via NuGet to .NET 4.0. The idea is to leverage ADFS Idp Initiated Login page and follow the redirects to extract the SAML Response that happens during the process of logging in to a SAML-Protocol endpoint.

Requirements

You have to create a SAML-Protocol Assertion Endpoint with POST binding in your reliant party configuration. This endpoint can co-exist with a Federation endpoint.

image

Code

I put together two samples. One that shows step-by-step using a Windows Forms application how to acquire a SAML Response (you can download it here):

image

Windows Forms Snippet

  1. using System;

  2. using System.Collections.Generic;

  3. using System.ComponentModel;

  4. using System.Data;

  5. using System.Drawing;

  6. using System.Linq;

  7. using System.Net.Http;

  8. using System.Text;

  9. using System.Threading.Tasks;

  10. using System.Windows.Forms;

  11. using System.Xml;

  12. using System.Text.RegularExpressions;

  13. using System.Web;

  14. using System.IO;

  15. using System.IO.Compression;

  16. //The code samples are provided AS IS without warranty of any kind.

  17. // Microsoft disclaims all implied warranties including, without limitation,

  18. // any implied warranties of merchantability or of fitness for a particular purpose.

  19. /*

  20. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.

  21. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts

  22. be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption,

  23. loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts

  24. or documentation, even if Microsoft has been advised of the possibility of such damages.

  25. */

  26. namespace GetSaml

  27. {

  28.     public partial class Form1 : Form

  29.     {

  30.         public Form1()

  31.         {

  32.             InitializeComponent();

  33.         }

  34.         private string getUrl = null;

  35.         private string GetUrl

  36.         {

  37.             get

  38.             {

  39.                 if (!String.IsNullOrEmpty(getUrl))

  40.                     return getUrl;

  41.                 StringBuilder domain = new StringBuilder();

  42.                 domain.Append(Environment.GetEnvironmentVariable("USERDNSDOMAIN"));

  43.                 if (domain.Length > 0)

  44.                 {

  45.                     domain.Clear();

  46.                     domain.Append(Environment.UserDomainName);

  47.                 }

  48.                 

  49.                 //return String.Format("https://{0}.{1}.lab/adfs/ls/MyIdpInitiatedSignOn.aspx?loginToRp=https://mysyte.com", Environment.MachineName.ToLower(), Environment.UserDomainName.ToLower());

  50.                 return String.Format("https://{0}.{1}.lab/adfs/ls/IdpInitiatedSignOn.aspx", Environment.MachineName.ToLower(), Environment.UserDomainName.ToLower());

  51.             }

  52.         }

  53.         private void Form1_Load(object sender, EventArgs e)

  54.         {

  55.             textBox1.Text = GetUrl;

  56.         }

  57.         protected List<KeyValuePair<string, string>> forms;

  58.         private HttpClient client = null;

  59.         private HttpClientHandler handler;

  60.         private HttpClient Client

  61.         {

  62.             get

  63.             {

  64.                 if (client == null)

  65.                 {

  66.                     handler = new HttpClientHandler();

  67.                     handler.UseDefaultCredentials = true;

  68.                     handler.AllowAutoRedirect = false;

  69.                     handler.CookieContainer = new System.Net.CookieContainer();

  70.                     handler.UseCookies = true;

  71.                     client = new HttpClient(handler);

  72.                     client.MaxResponseContentBufferSize = 256000;

  73.                     client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");

  74.                     client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");

  75.                     client.DefaultRequestHeaders.ExpectContinue = false;

  76.                 }

  77.                 return client;

  78.             }

  79.         }

  80.         private async void button1_Click(object sender, EventArgs e)

  81.         {

  82.             string url = String.Format("{0}?loginToRp={1}", textBox1.Text, HttpUtility.UrlEncode(comboBox1.SelectedItem.ToString()));

  83.             // Limit the max buffer size for the response so we don't get overwhelmed

  84.             HttpResponseMessage result;

  85.             textBox3.Text="============== Start ===============";

  86.             var nl = Environment.NewLine;

  87.        

  88.             string text;

  89.             do

  90.             {

  91.                 textBox3.AppendText(String.Format("{1}********** GET {0}{1}", url, Environment.NewLine));

  92.                 result = await Client.GetAsync(url);

  93.                 text = await result.Content.ReadAsStringAsync();

  94.                 IEnumerable<string> values;

  95.                 if(result.Headers.TryGetValues("location", out values))

  96.                 {

  97.                     foreach(string s in values)

  98.                     {

  99.                         if (s.StartsWith("/"))

  100.                         {

  101.                             url = url.Substring(0, url.IndexOf("/adfs/ls")) + s;

  102.                         }

  103.                         else

  104.                             url = s;

  105.                     }

  106.                 } else

  107.                 {

  108.                     url = "";

  109.                 }

  110.                 textBox3.AppendText(String.Format("{0}[Headers]{0}", Environment.NewLine));

  111.                 foreach(var pair in result.Headers)

  112.                 {

  113.                     string key = pair.Key;

  114.                     foreach(var val in pair.Value)

  115.                         textBox3.AppendText(String.Format(" {0}={1}{2}", key, val, Environment.NewLine));

  116.                 }

  117.                 textBox3.AppendText(text);

  118.             } while (!String.IsNullOrEmpty(url));

  119.             Regex reg = new Regex("SAMLResponse\\W+value\\=\\\"([^\\\"]+)\\\"");

  120.             MatchCollection matches = reg.Matches(text);

  121.             string last = null;

  122.             foreach (Match m in matches)

  123.             {

  124.                 last = m.Groups[1].Value;

  125.                 textBox3.AppendText(String.Format(" {1}{1}{1}SAMLResponse={0}{1}", last, Environment.NewLine));

  126.             }

  127.             if(last != null)

  128.             {

  129.                 byte[] decoded = Convert.FromBase64String(last);

  130.                 string deflated = Encoding.UTF8.GetString(decoded);

  131.                 XmlDocument doc = new XmlDocument();

  132.                 StringBuilder sb = new StringBuilder();

  133.                 doc.LoadXml(deflated);

  134.                 using(StringWriter sw = new StringWriter(sb))

  135.                 {

  136.                     using (XmlTextWriter tw = new XmlTextWriter(sw) { Formatting = Formatting.Indented })

  137.                     {

  138.                         doc.WriteTo(tw);

  139.                     }

  140.                 }

  141.                 textBox3.AppendText(String.Format(" {1}{1}{1}XML Formated:{1}{0}{1}", sb.ToString(), Environment.NewLine));

  142.                 

  143.             }

  144.         }

  145.         private void DysplayError(Exception ex)

  146.         {

  147.             MessageBox.Show(String.Format("Error: {0}{1}Stack:{1}{2}", ex.Message, Environment.NewLine, ex.StackTrace));

  148.         }

  149.         private async void button2_Click(object sender, EventArgs e)

  150.         {

  151.             try

  152.             {

  153.                 var response = await Client.GetAsync(textBox1.Text);

  154.                 response.EnsureSuccessStatusCode();

  155.                 comboBox1.Items.Clear();

  156.                 string text = await response.Content.ReadAsStringAsync();

  157.                 Regex reg = new Regex("option\\W+value\\=\\\"([^\\\"]+)\\\"");

  158.                 MatchCollection matches = reg.Matches(text);

  159.                 foreach(Match m in matches)

  160.                 {

  161.                     comboBox1.Items.Add(m.Groups[1].Value);

  162.                 }

  163.                 if (matches.Count == 0)

  164.                 {

  165.                     MessageBox.Show("No Reliant Party found");

  166.                     button1.Enabled = false;

  167.                 } else

  168.                 {

  169.                     button1.Enabled = true;

  170.                     comboBox1.SelectedIndex = 0;

  171.                 }

  172.             } catch(Exception ex)

  173.             {

  174.                 DysplayError(ex);

  175.                 return;

  176.             }

  177.         }

  178.     }

  179. }

I also organized the code in a class library that can be used in any C# application. You can download the code and test application here.

Class to get SAML Response

  1. using System;

  2. using System.Collections.Generic;

  3. using System.Text;

  4. using System.Threading.Tasks;

  5. using System.Net.Http;

  6. using System.Text.RegularExpressions;

  7. using System.Web;

  8. using System.Xml;

  9. using System.IO;

  10. //The code samples are provided AS IS without warranty of any kind.

  11. // Microsoft disclaims all implied warranties including, without limitation,

  12. // any implied warranties of merchantability or of fitness for a particular purpose.

  13. /*

  14. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.

  15. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts

  16. be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption,

  17. loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts

  18. or documentation, even if Microsoft has been advised of the possibility of such damages.

  19. */

  20. namespace Microsoft.Samples.AdfsSaml

  21. {

  22.     /// <summary>

  23.     /// Class to get a SAML response from ADFS.

  24.     /// it requires that the SAML endpoint with POST binding is configured in ADFS

  25.     /// </summary>

  26.     public class SamlResponse

  27.     {

  28.         /// <summary>

  29.         /// If true, ADFS url will not be validated

  30.         /// </summary>

  31.         public bool EnableRawUrl

  32.         {

  33.             get;

  34.             set;

  35.         }

  36.         private Uri serverAddress = null;

  37.         private HttpClient client = null;

  38.         private HttpClientHandler handler;

  39.         private HttpClient Client

  40.         {

  41.             get

  42.             {

  43.                 if (client == null)

  44.                 {

  45.                     handler = new HttpClientHandler();

  46.                     handler.UseDefaultCredentials = true;

  47.                     handler.AllowAutoRedirect = false;

  48.                     handler.CookieContainer = new System.Net.CookieContainer();

  49.                     handler.UseCookies = true;

  50.                     client = new HttpClient(handler);

  51.                     client.MaxResponseContentBufferSize = 256000;

  52.                     client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");

  53.                     client.DefaultRequestHeaders.Add("Connection", "Keep-Alive");

  54.                     client.DefaultRequestHeaders.ExpectContinue = false;

  55.                 }

  56.                 return client;

  57.             }

  58.         }

  59.         /// <summary>

  60.         /// Url of ADFS server (e.g. https://adfs.contoso.com)

  61.         /// </summary>

  62.         public Uri ServerAddress

  63.         {

  64.             get

  65.             {

  66.                 return serverAddress;

  67.             }

  68.             set

  69.             {

  70.                 if(EnableRawUrl)

  71.                 {

  72.                     serverAddress = value;

  73.                     return;

  74.                 }

  75.                 string host = value.Host;

  76.                 string scheme = value.Scheme;

  77.                 if(scheme != "https")

  78.                 {

  79.                     throw new ArgumentException("ADFS rquires scheme https. Set EnableRawUrl to true to override it", "ServerAddress");

  80.                 }

  81.                 serverAddress = new Uri(String.Format("https://{0}//adfs/ls/IdpInitiatedSignOn.aspx", host));

  82.             }

  83.         }

  84.         /// <summary>

  85.         /// Initialize the class

  86.         /// </summary>

  87.         public SamlResponse()

  88.         {

  89.         }

  90.         /// <summary>

  91.         /// Initialize the class

  92.         /// </summary>

  93.         /// <param name="Url">Urn of reliant party as defined in ADFS. Ise GetReliantPArtyCollection to get the list</param>

  94.         /// <param name="IsRawUrl">If true, ADFS url will not be validated</param>

  95.         public SamlResponse(Uri Url, bool IsRawUrl = false)

  96.         {

  97.             EnableRawUrl = IsRawUrl;

  98.             ServerAddress = Url;

  99.         }

  100.         private async Task<string[]> GetReliantPartyCollectionInternal()

  101.         {

  102.             if (serverAddress == null)

  103.             {

  104.                 throw new NullReferenceException("ServerAddress was not set");

  105.             }

  106.             var response = await Client.GetAsync(serverAddress);

  107.             response.EnsureSuccessStatusCode();

  108.             string text = await response.Content.ReadAsStringAsync();

  109.             Regex reg = new Regex("option\\W+value\\=\\\"([^\\\"]+)\\\"");

  110.             MatchCollection matches = reg.Matches(text);

  111.             if(matches.Count == 0)

  112.             {

  113.                 return null;

  114.             }

  115.             string[] rps = new string[matches.Count];

  116.             uint i = 0;

  117.             foreach (Match m in matches)

  118.             {

  119.                 rps[i++]=m.Groups[1].Value;

  120.             }

  121.             return rps;

  122.         }

  123.         /// <summary>

  124.         /// Get the list of Reliant Parties with SAML endpoint with binding POST in ADFS

  125.         /// </summary>

  126.         public string[] GetReliantPartyCollection()

  127.         {

  128.             return GetReliantPartyCollectionInternal().Result;

  129.         }

  130.         /// <summary>

  131.         /// Retrieve the SAML Response from ADFS for ReliantPartyUrn

  132.         /// </summary>

  133.         /// <param name="ReliantPartyUrn">Urn of reliant party as defined in ADFS. Ise GetReliantPArtyCollection to get the list</param>

  134.         public string RequestSamlResponse(string ReliantPartyUrn)

  135.         {

  136.             if(serverAddress == null)

  137.             {

  138.                 throw new NullReferenceException("ServerAddress was not set");

  139.             }

  140.             if(String.IsNullOrEmpty(ReliantPartyUrn) && !EnableRawUrl)

  141.             {

  142.                 throw new ArgumentException("Reliant Party Urn cannot be empty if EnableRawUrl is not true");

  143.             }

  144.             return SamlResponseInternal(ReliantPartyUrn).Result;

  145.             

  146.         }

  147.         private async Task<string> SamlResponseInternal(string ReliantPartyUrn)

  148.         {

  149.             StringBuilder url = new StringBuilder(String.Format("{0}?loginToRp={1}", serverAddress, HttpUtility.UrlEncode(ReliantPartyUrn)));

  150.             HttpResponseMessage result;

  151.             

  152.             do

  153.             {

  154.                 result = await Client.GetAsync(url.ToString());

  155.                 string text = await result.Content.ReadAsStringAsync();

  156.                 IEnumerable<string> values;

  157.                 if (result.Headers.TryGetValues("location", out values))

  158.                 {

  159.                     foreach (string s in values)

  160.                     {

  161.                         if (s.StartsWith("/"))

  162.                         {

  163.                             string newUrl = url.ToString().Substring(0, url.ToString().IndexOf("/adfs/ls"));

  164.                             url.Clear();

  165.                             url.Append(newUrl);

  166.                             url.Append(s);

  167.                         }

  168.                         else

  169.                         {

  170.                             url.Clear();

  171.                             url.Append(s);

  172.                         }

  173.                     }

  174.                 }

  175.                 else

  176.                 {

  177.                     url.Clear();

  178.                 }

  179.                 if (url.Length == 0)

  180.                 {

  181.                     Regex reg = new Regex("SAMLResponse\\W+value\\=\\\"([^\\\"]+)\\\"");

  182.                     MatchCollection matches = reg.Matches(text);

  183.                     foreach (Match m in matches)

  184.                     {

  185.                         return m.Groups[1].Value;

  186.                     }

  187.                 }

  188.             } while (url.Length > 0);

  189.             throw new InvalidOperationException("Unable to get a SAMLP response from ADFS");

  190.         }

  191.         public static string SamlToXmlString(string EncodedResponse)

  192.         {

  193.             byte[] decoded = Convert.FromBase64String(EncodedResponse);

  194.             string deflated = Encoding.UTF8.GetString(decoded);

  195.             XmlDocument doc = new XmlDocument();

  196.             StringBuilder sb = new StringBuilder();

  197.             doc.LoadXml(deflated);

  198.             using (StringWriter sw = new StringWriter(sb))

  199.             {

  200.                 using (XmlTextWriter tw = new XmlTextWriter(sw) { Formatting = Formatting.Indented })

  201.                 {

  202.                     doc.WriteTo(tw);

  203.                 }

  204.             }

  205.             return sb.ToString();

  206.         }

  207.     }

  208. }

Comments

  • Anonymous
    September 22, 2014
    Most excellent utility.  Thank you.

  • Anonymous
    October 23, 2014
    I have attempted to use the Form to pull a SAMLResponse from the AWS Relying Party trust off of my ADFS server however it doesn't show the SAMLResponse output anywhere. Thoughts?

  • Anonymous
    October 23, 2014
    The comment has been removed

  • Anonymous
    October 27, 2014
    Yes I have ran this against the 2 other sites in the Target Name drop down list. None show the SAMLResponse. It's a lot of text including SAMLRequest and  Page information. Just doesn't include your SAMLResponse shown above. I simply downloaded the Form code, and ran the .exe and put in my adfs server name and then chose the AWS site.

  • Anonymous
    October 27, 2014
    Todd, Can you show me an output?

  • Anonymous
    October 27, 2014
    Do I need to be installing anything before running the GetSaml.exe? I am not a master coder by any means so I was running the form rather than trying to do a C# application. Here is the output: ============== Start =============== ********** GET https://ADFS/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn%3aamazon%3awebservices [Headers] Pragma=no-cache Cache-Control=no-cache Date=Mon, 27 Oct 2014 19:40:24 GMT Location=https://ADFS/adfs/ls/?SAMLRequest=7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ%2fff%2fz9cZmQBbPbOStrJniGAqsgfP358Hz8iHjfZolw9Ol638%2bWr%2fBet86ZNz55%2b9tHvn%2b09zCf5w3z7PLu3u70%2fvT%2fbzvJ7B9v39w5me7uzbDp9%2bPCj9Cfzuimq5Wcf7Y13PkrPmmadny2bNlu29NHO7v727s723oM3uw8f7e882n84%2fnR356c%2bSp9SL8Uya%2fnNeduumkd377Zt0zbjts5mxfKizafzZVVWF0XejKfV4m42O2%2fuls3dj9KTatnkgL%2bul4%2bqrCmaR8tskTeP2umj18dfPH9EqDyaSqNH62WzyqfFeZHPPkrfLcpl84gHvPntVV211bQqPzp6zEOq5dXNL2VNk9cY0kdHGNLtRkSvXBbTvLnb1uumfXxXujt6TIOcFQDWvGfXj4%2fXsyJfTvNXROO6mOJT9%2bERoGSL7AfV8tFVPjG9P75rG7hfAwB3HUL0R59njv4f&Signature=haV26bjGqbuPcg0sywh3h3pwsbZ3WdPy20r2GTax%2b4Or0qVJ9rZiIi4CQToev83N0Iyah%2bi%2btbowVj8Au7HYau43vlSkz%2foQondUYEnkUNHi8PaExLIXZ8vPCVYCWSu%2bbIEHTQh%2fOiGFNRFL47o7eGfdFoc87rmHcTWrxbJyO9BdiHT%2fVvG6h5LjtD%2fk1YbR0ZcMwnJlIujnaYVJ8mp9kc908vsG4Jp8yyUD8f1R09TXjgEGV9oExOjcOHcZf6KDwfp6vRKGXjhaBAivdIbHzlCUsfSjrJIukuif6ng6FKvvqBd%2bNh%2fMjoYXIiGcQ%2bSyPTKsnc%2fJvHM0RKIhvByBgOf2G2ieTlnU2aPf5Vwnzo1nTUwI7PVvIWRDfI1d727pDBhK%2f%2fXFDe%2b9nK8BF3MOYdqWE650ISwhPQyQP9d75DhOdG%2fd%2fRp4q8ogjyb%2fv4oy02szfH66Ezlx1elXn7WQsKC41FgyMFmhqvqJsn7In7tgmXXkKIFhJN13bOIDIqXnef8uZsDGYWG8topaYgnCtgVa6KQr9fQxiI9ZmeJ1TpuXG1WDXmGcwZ4U3yq2hGFebliAzhqj9ePgVShwrFTctKifjrMugBdDE8gQLaQXXBSJC0F54gfG9jYUksYwxT9RUfOB%2b0NvVq4lhIxc3n0nO%2fN3AShDG2jRjzdQ5KTsO4c%3d&SigAlg=http%3a%2f%2fwww.w3.org%2f2001%2f04%2fxmldsig-more%23rsa-sha256 Server=Microsoft-IIS/7.5 X-AspNet-Version=2.0.50727 X-Powered-By=ASP.NET

  • Anonymous
    October 27, 2014
    <html><head></head><body> <h2>Object moved to <a href="https://ADFS/adfs/ls/?SAMLRequest=7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ%2fff%2fz9cZmQBbPbOStrJniGAqsgfP358Hz8iHjfZolw9Ol638%2bWr%2fBet86ZNz55%2b9tHvn%2b09zCf5w3z7PLu3u70%2fvT%2fbzvJ7B9v39w5me7uzbDp9%2bPCj9Cfzuimq5Wcf7Y13PkrPmmadny2bNlu29NHO7v727s723oM3uw8f7e882n84%2fnR356c%2bSp9SL8Uya%2fnNeduumkd377Zt0zbjts5mxfKizafzZVVWF0XejKfV4m42O2%2fuls3dj9KTatnkgL%2bul4%2bqrCmaR8tskTeP2umj18dfPH9EqDyaSqNH62WzyqfFeZHPPkrfLcpl84gHvPntVV211bQqPzp6zEOq5dXNL2VNk9cY0kdHGNLtRkSvXBbTvLnb1uumfXxXujt6TIOcFQDWvGfXj4%2fXsyJfTvNXROO6mOJT9%2bERoGSL7AfV8tFVPjG9P75rG7hfAwB3HUL0R59njv4f&Signature=haV26bjGqbuPcg0sywh3h3pwsbZ3WdPy20r2GTax%2b4Or0qVJ9rZiIi4CQToev83N0Iyah%2bi%2btbowVj8Au7HYau43vlSkz%2foQondUYEnkUNHi8PaExLIXZ8vPCVYCWSu%2bbIEHTQh%2fOiGFNRFL47o7eGfdFoc87rmHcTWrxbJyO9BdiHT%2fVvG6h5LjtD%2fk1YbR0ZcMwnJlIujnaYVJ8mp9kc908vsG4Jp8yyUD8f1R09TXjgEGV9oExOjcOHcZf6KDwfp6vRKGXjhaBAivdIbHzlCUsfSjrJIukuif6ng6FKvvqBd%2bNh%2fMjoYXIiGcQ%2bSyPTKsnc%2fJvHM0RKIhvByBgOf2G2ieTlnU2aPf5Vwnzo1nTUwI7PVvIWRDfI1d727pDBhK%2f%2fXFDe%2b9nK8BF3MOYdqWE650ISwhPQyQP9d75DhOdG%2fd%2fRp4q8ogjyb%2fv4oy02szfH66Ezlx1elXn7WQsKC41FgyMFmhqvqJsn7In7tgmXXkKIFhJN13bOIDIqXnef8uZsDGYWG8topaYgnCtgVa6KQr9fQxiI9ZmeJ1TpuXG1WDXmGcwZ4U3yq2hGFebliAzhqj9ePgVShwrFTctKifjrMugBdDE8gQLaQXXBSJC0F54gfG9jYUksYwxT9RUfOB%2b0NvVq4lhIxc3n0nO%2fN3AShDG2jRjzdQ5KTsO4c%3d&SigAlg=http%3a%2f%2fwww.w3.org%2f2001%2f04%2fxmldsig-more%23rsa-sha256">here</a>.</h2> </body></html> ********** GET https://ADFS/adfs/ls/?SAMLRequest=7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ%2fff%2fz9cZmQBbPbOStrJniGAqsgfP358Hz8iHjfZolw9Ol638%2bWr%2fBet86ZNz55%2b9tHvn%2b09zCf5w3z7PLu3u70%2fvT%2fbzvJ7B9v39w5me7uzbDp9%2bPCj9Cfzuimq5Wcf7Y13PkrPmmadny2bNlu29NHO7v727s723oM3uw8f7e882n84%2fnR356c%2bSp9SL8Uya%2fnNeduumkd377Zt0zbjts5mxfKizafzZVVWF0XejKfV4m42O2%2fuls3dj9KTatnkgL%2bul4%2bqrCmaR8tskTeP2umj18dfPH9EqDyaSqNH62WzyqfFeZHPPkrfLcpl84gHvPntVV211bQqPzp6zEOq5dXNL2VNk9cY0kdHGNLtRkSvXBbTvLnb1uumfXxXujt6TIOcFQDWvGfXj4%2fXsyJfTvNXROO6mOJT9%2bERoGSL7AfV8tFVPjG9P75rG7hfAwB3HUL0R59njv4f&Signature=haV26bjGqbuPcg0sywh3h3pwsbZ3WdPy20r2GTax%2b4Or0qVJ9rZiIi4CQToev83N0Iyah%2bi%2btbowVj8Au7HYau43vlSkz%2foQondUYEnkUNHi8PaExLIXZ8vPCVYCWSu%2bbIEHTQh%2fOiGFNRFL47o7eGfdFoc87rmHcTWrxbJyO9BdiHT%2fVvG6h5LjtD%2fk1YbR0ZcMwnJlIujnaYVJ8mp9kc908vsG4Jp8yyUD8f1R09TXjgEGV9oExOjcOHcZf6KDwfp6vRKGXjhaBAivdIbHzlCUsfSjrJIukuif6ng6FKvvqBd%2bNh%2fMjoYXIiGcQ%2bSyPTKsnc%2fJvHM0RKIhvByBgOf2G2ieTlnU2aPf5Vwnzo1nTUwI7PVvIWRDfI1d727pDBhK%2f%2fXFDe%2b9nK8BF3MOYdqWE650ISwhPQyQP9d75DhOdG%2fd%2fRp4q8ogjyb%2fv4oy02szfH66Ezlx1elXn7WQsKC41FgyMFmhqvqJsn7In7tgmXXkKIFhJN13bOIDIqXnef8uZsDGYWG8topaYgnCtgVa6KQr9fQxiI9ZmeJ1TpuXG1WDXmGcwZ4U3yq2hGFebliAzhqj9ePgVShwrFTctKifjrMugBdDE8gQLaQXXBSJC0F54gfG9jYUksYwxT9RUfOB%2b0NvVq4lhIxc3n0nO%2fN3AShDG2jRjzdQ5KTsO4c%3d&SigAlg=http%3a%2f%2fwww.w3.org%2f2001%2f04%2fxmldsig-more%23rsa-sha256

  • Anonymous
    October 27, 2014
    [Headers] Pragma=no-cache Cache-Control=no-cache Date=Mon, 27 Oct 2014 19:40:24 GMT Server=Microsoft-IIS/7.5 X-AspNet-Version=2.0.50727 X-Powered-By=ASP.NET <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "www.w3.org/.../xhtml1-transitional.dtd"> <html xmlns="www.w3.org/.../xhtml" dir="ltr"> <head><meta http-equiv="X-UA-Compatible" content="IE=8" /><link rel="stylesheet" type="text/css" href="MasterPages/StyleSheet.css" /><meta name="robots" content="noindex, nofollow" /></head> <body>    <form name="aspnetForm" method="post" action="/adfs/ls/?SAMLRequest=7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ%2fff%2fz9cZmQBbPbOStrJniGAqsgfP358Hz8iHjfZolw9Ol638%2bWr%2fBet86ZNz55%2b9tHvn%2b09zCf5w3z7PLu3u70%2fvT%2fbzvJ7B9v39w5me7uzbDp9%2bPCj9Cfzuimq5Wcf7Y13PkrPmmadny2bNlu29NHO7v727s723oM3uw8f7e882n84%2fnR356c%2bSp9SL8Uya%2fnNeduumkd377Zt0zbjts5mxfKizafzZVVWF0XejKfV4m42O2%2fuls3dj9KTatnkgL%2bul4%2bqrCmaR8tskTeP2umj18dfPH9EqDyaSqNH62WzyqfFeZHPPkrfLcpl84gHvPntVV211bQqPzp6zEOq5dXNL2VNk9cY0kdHGNLtRkSvXBbTvLnb1uumfXxXujt6TIOcFQDWvGfXj4%2fXsyJfTvNXROO6mOJT9%2bERoGSL7AfV8tFVPjG9P75rG7hfAwB3HUL0R59njv4f&Signature=haV26bjGqbuPcg0sywh3h3pwsbZ3WdPy20r2GTax%2b4Or0qVJ9rZiIi4CQToev83N0Iyah%2bi%2btbowVj8Au7HYau43vlSkz%2foQondUYEnkUNHi8PaExLIXZ8vPCVYCWSu%2bbIEHTQh%2fOiGFNRFL47o7eGfdFoc87rmHcTWrxbJyO9BdiHT%2fVvG6h5LjtD%2fk1YbR0ZcMwnJlIujnaYVJ8mp9kc908vsG4Jp8yyUD8f1R09TXjgEGV9oExOjcOHcZf6KDwfp6vRKGXjhaBAivdIbHzlCUsfSjrJIukuif6ng6FKvvqBd%2bNh%2fMjoYXIiGcQ%2bSyPTKsnc%2fJvHM0RKIhvByBgOf2G2ieTlnU2aPf5Vwnzo1nTUwI7PVvIWRDfI1d727pDBhK%2f%2fXFDe%2b9nK8BF3MOYdqWE650ISwhPQyQP9d75DhOdG%2fd%2fRp4q8ogjyb%2fv4oy02szfH66Ezlx1elXn7WQsKC41FgyMFmhqvqJsn7In7tgmXXkKIFhJN13bOIDIqXnef8uZsDGYWG8topaYgnCtgVa6KQr9fQxiI9ZmeJ1TpuXG1WDXmGcwZ4U3yq2hGFebliAzhqj9ePgVShwrFTctKifjrMugBdDE8gQLaQXXBSJC0F54gfG9jYUksYwxT9RUfOB%2b0NvVq4lhIxc3n0nO%2fN3AShDG2jRjzdQ5KTsO4c%3d&SigAlg=http%3a%2f%2fwww.w3.org%2f2001%2f04%2fxmldsig-more%23rsa-sha256" id="aspnetForm"> <div> <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTY2MTc3NjUzM2Rk" /> </div> <div>

  • Anonymous
    October 27, 2014
    Are you calling from the same machine ADFS is installed? If so, it will not work because of the loopback check (which you can disable). Short of it, the SAMLRequest seems to be right.

  • Anonymous
    October 27, 2014
    Character limit, I apologize for having to break it up like this.

  • Anonymous
    October 27, 2014
    Nope, I am running this from my own machine and targeting the ADFS machine. I was looking to get the SAMLResponse which it just is not giving me in the output.

  • Anonymous
    October 27, 2014
    I am running the .exe from my own machined and targeting the ADFS server and AWS site. Weird I am not getting that SAMLResponse I need. I should simply just be able to download your code form .exe and run it right?

  • Anonymous
    October 27, 2014
    Calling from my machine and targeting the ADFS server and AWS relying site I configured. Just doesn't have the SAMLResponse I need to run an API command. I should just be able to download and run the getsaml.exe and target this right, no extra config?

  • Anonymous
    June 29, 2015
    Thank you for this article, Please advise me how to configure ADFs to Test this code. Thank you.

  • Anonymous
    July 12, 2015
    I'm new to SSO, ADFS and the like, but unfortunately I got thrown into a project that wants to use their legacy web forms login page but still use the ADFS federation to be able to seamlessly navigate to a partner's site without logging in there as well.  Is the idea of this project that I can build a request using the markup obtained by running your tool and then posting that page to achieve the login?

  • Anonymous
    July 12, 2015
    Tim, Federation is a different protocol that is covered in Windows Identity Foundation (WIF). There are several tutorials on how to do that. This is for SAML-Protocol which is not supported in WIF.

  • Anonymous
    July 12, 2015
    Rod, I don't/can't use passive federation because the client demands we use their login page.  So I am not fixated on using WIF if I cannot use that in addition to using the existing legacy login page.  I have not found an example of using active federation in a web forms app either, at least not one that relies upon classes and members of classes that have been deprecated.  So if you have any pointers on how I can tweak your code to work in my situation or some other way to accomplish my requirement, I'm all ears.

  • Anonymous
    July 12, 2015
    The comment has been removed

  • Anonymous
    July 12, 2015
    Tim, You need to use WS-Trust 1.3 to request a bearer token from ADFS and use this token to call the 3rd-party: leastprivilege.com/.../wcf-and-identity-in-net-4-5-external-authentication-with-ws-trust

  • Anonymous
    July 13, 2015
    Rod, thanks for the link.  I had already found that link.  My problem is that the sample code does not compile ( WSTrustChannelFactory no longer has a "Credentials" member, for example) and I am not familiar enough with the inner workings of WS-Trust to determine the current way of accomplishing what the sample code suggests.

  • Anonymous
    July 13, 2015
    Tim, Right now I am on vacation without a development environment. Post a question to the WIF forum at MSDN so someone can follow up with this. Don't forget to mention your .NET version.

  • Anonymous
    December 22, 2015
    Where is the authentication?  Shouldn't you post the username, password and SAMLResponse to the relying party? I've extracted the contents of the authentication flow between browser -> RP, browser -> ADFS and browser -> RP again with Fiddler and wanted to replicate in code this without the ADFS login form showing. Its a poor man's version of single sign on.   Its similar to what you're doing, but its brute force and also could it be a kind of replay attack? What is the Single Sign On solution for Windows7 development using ADFS 3.0?

  • Anonymous
    December 23, 2015
    Daniel, Password is not passed over, but a NTLM or Kerberos token instead. SAML tokens do not contain a password, only the claims configured for the reliant party (RP). If the RP configuration includes a signing certificate even the claims are encrypted at message level, so Fiddler reverse-engineer is of no use. ADFS does not make a brute force attack any easier. My application (and library) is not getting any data that would not be available to the person authenticating.

  • Anonymous
    April 01, 2016
    The comment has been removed

    • Anonymous
      October 11, 2017
      So did you get this to work? Are you authenticating with ADFS in terms of retrieving specific information our to be authenticated for SSO purposes?We're wanting to use our custom app to authenticate with ADFS for SSO purposes but without actually directing the user to the ADFS IdpInitiatedSignOn.aspx page. From what I've read and tried, this is not possible and the request to authenticate with ADFS to get an SSO token has to originate from the ADFS sign on page...What we're wanting to do:: user signs into our custom app, custom app then authenticates said user to ADFS ("in the background") returning the authenticated token back to our custom app. Now linking to any relying party trust apps connected to ADFS via our custom app the user will already be signed in....We are wanting to due this to to multiple reasons, including: our custom app has multiple audiences, both with AD accounts and those without.. 2. the ADFS sign on page is hardly customizable, wouldn't be able to make it look anything like our custom app login page.
  • Anonymous
    September 11, 2018
    Hi Rodney,Currently working on a project where I need to extract the SAML2 Protocol Response just like you have with your C# code. When i run the downloaded page, either the pre-compiled form program or recompiled on my machine, i get the same issue as "Todd - October 23, 2014" posted. In my instance i can see get several get requests with returned header output (mainly cookie related) and then a heap of html and JavaScript code. No where in the output can i find the SAML Response.Just wondering if you have any ideas of what could be wrong? We are using our internal ADFS setup... Not AWS as Todd was.CheersCraig

  • Anonymous
    September 11, 2018
    Hi Rodney,Currently working on a project where I need to extract the SAML2 Protocol Response just like you have with your C# code. When i run the downloaded page, either the pre-compiled form program or recompiled on my machine, i get the same issue as "Todd - October 23, 2014" posted. In my instance i can see get several get requests with returned header output (mainly cookie related) and then a heap of html and JavaScript code. No where in the output can i find the SAML Response.Just wondering if you have any ideas of what could be wrong? We are using our internal ADFS setup... Not AWS as Todd was.CheersCraig

    • Anonymous
      September 14, 2018
      The code was written for ADFS 2.0 and it does not work on ADFS 3.0.
  • Anonymous
    September 11, 2018
    Hi Rodney, This looks great!!! I am currently working on a project where I need to extract the SAML2 Protocol Response just like you have with your C# code. When i run the downloaded page, either the pre-compiled form program or recompiled on my machine, i get the same issue as "Todd - October 23, 2014" posted. In my instance i can see get several get requests with returned header output (mainly cookie related) and then a heap of html and JavaScript code. No where in the output can i find the SAML Response. Just wondering if you have any ideas of what could be wrong? We are using our internal ADFS setup... Not AWS as Todd was. Cheers Craig

    • Anonymous
      September 13, 2018
      Hi Craig_Han,This was designed for ADFS 2.0. If you use ADFS 3.0 it will not work.I will revisit the code at some point to adapt to ADFS 3.0.