使用来自 SAML 令牌的 FedAuth cookie 调用 UI 控制器
Call a UI controller with FedAuth cookie from SAML token
我们正在尝试使一些集成测试自动化。因此,我们希望能够以编程方式调用 UI 控制器,以便与卷轴用户所做的一样。出于不同的原因,我们不想使用 UI 测试套件。
问题是我们使用 SSO Windows 身份验证与 WIF 的 WS 联合安全。在配置中,我们使用 passiveRedirectEnabled="true" 以便每次会话 cookie 不存在、无效或过期时,页面都会重定向到 AD FS STS 端点 ("/adfs/ls/")。结果再次重定向回 Web.config 文件中 "reply" 属性指定的页面。
当我查看 Fiddler 时,我清楚地看到第二个重定向(从 AD FS STS 返回)具有 302 状态 returns 对浏览器的 "Set-Cookie : FedAuth=77u/PD94bWwg..." 指令。使用 FedAuth cookie 调用回复页面,一切正常。
有没有办法模拟这种行为并能够使用正确的 FedAuth cookie 调用 UI 控制器?请不要使用 SharePoint,这与它无关。
我终于能够重现我在 Fiddler 中看到的步骤来模仿浏览器。我会把代码放在这里,希望它能对你们中的一些人有所帮助。它不是很干净,它更像是一种 POC 模式,但它仍然可以提供帮助。请注意,在某些请求中我不得不允许自动重定向,而另一些请求我不得不阻止它。
感谢我的同事 Dominique Pothier,他在这方面帮助了我很多。
//First request to the secured site
var request =
(HttpWebRequest)WebRequest.Create("https://mysite.mycompany.ca/");
request.Method = "GET";
request.UseDefaultCredentials = true;
request.PreAuthenticate = true;
request.AllowAutoRedirect = false;
var httpResponse = (HttpWebResponse)request.GetResponse();
//Redirects to the STS based on the response from the first call, posting the ws-federations infos along
request =
(HttpWebRequest)WebRequest.Create(httpResponse.Headers["Location"]);
request.UseDefaultCredentials = true;
request.PreAuthenticate = true;
request.Host = "sts.mycompany.ca";
request.AllowAutoRedirect = true;
request.UserAgent =
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
var nameValueCollection = new NameValueCollection { { "Cache-Control", "max-age=0" } };
request.Headers.Add(nameValueCollection);
nameValueCollection = new NameValueCollection { { "Upgrade-Insecure-Requests", "1" } };
request.Headers.Add(nameValueCollection);
nameValueCollection = new NameValueCollection { { "Accept-Encoding", "gzip, deflate, sdch" } };
request.Headers.Add(nameValueCollection);
nameValueCollection = new NameValueCollection { { "Accept-Language", "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4" } };
request.Headers.Add(nameValueCollection);
httpResponse = (HttpWebResponse)request.GetResponse();
//Parse the response to get ws-federation infos
var responseStream = new StreamReader(httpResponse.GetResponseStream());
var responseData = responseStream.ReadToEnd();
var xmlReader = XmlReader.Create(new StringReader(responseData));
var wa = "";
var wresult = "";
var wctx = "";
while (xmlReader.Read())
{
if (xmlReader.GetAttribute("name") == "wa")
wa = xmlReader.GetAttribute("value");
if (xmlReader.GetAttribute("name") == "wresult")
wresult = xmlReader.GetAttribute("value");
if (xmlReader.GetAttribute("name") == "wctx")
wctx = xmlReader.GetAttribute("value");
}
httpResponse.Close();
//Redirects to the controller method we want to hit
request =
(HttpWebRequest)WebRequest.Create("https://mysite.mycompany.ca/Home/GetStates");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.AllowAutoRedirect = false;
//Add the cookie container to the response so that we can get the FedAuth cookie after the response
request.CookieContainer = new CookieContainer();
//Add the ws-federation infos from the last http request to the body of the new request
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
if (wa != null)
{
var waEncoded = HttpUtility.UrlEncode(wa);
var wresultEncoded = HttpUtility.UrlEncode(wresult);
var wctxEncoded = HttpUtility.UrlEncode(wctx);
var urlEncoded = "wa=" + waEncoded + "&wresult=" + wresultEncoded + "&wctx=" + wctxEncoded;
streamWriter.Write(urlEncoded);
streamWriter.Flush();
streamWriter.Close();
}
}
request.Referer = httpResponse.ResponseUri.OriginalString;
httpResponse = (HttpWebResponse)request.GetResponse();
var cookieContainer = request.CookieContainer;
//Use the FedAuth cookie that we got from last http call and add it to a new request to the controller and voila !
request =
(HttpWebRequest)WebRequest.Create("https://mysite.mycompany.ca/Home/GetStates");
request.Method = "GET";
nameValueCollection = new NameValueCollection { { "X-Requested-With", "XMLHttpRequest" } };
request.Headers.Add(nameValueCollection);
//Add the FedAuthCookie from last request
request.CookieContainer = cookieContainer;
request.Referer = "https://proacces-dev1.universitas.ca/";
httpResponse = (HttpWebResponse)request.GetResponse();
responseStream = new StreamReader(httpResponse.GetResponseStream());
responseData = responseStream.ReadToEnd();
Console.WriteLine(responseData);
Console.ReadLine();
我们正在尝试使一些集成测试自动化。因此,我们希望能够以编程方式调用 UI 控制器,以便与卷轴用户所做的一样。出于不同的原因,我们不想使用 UI 测试套件。
问题是我们使用 SSO Windows 身份验证与 WIF 的 WS 联合安全。在配置中,我们使用 passiveRedirectEnabled="true" 以便每次会话 cookie 不存在、无效或过期时,页面都会重定向到 AD FS STS 端点 ("/adfs/ls/")。结果再次重定向回 Web.config 文件中 "reply" 属性指定的页面。
当我查看 Fiddler 时,我清楚地看到第二个重定向(从 AD FS STS 返回)具有 302 状态 returns 对浏览器的 "Set-Cookie : FedAuth=77u/PD94bWwg..." 指令。使用 FedAuth cookie 调用回复页面,一切正常。
有没有办法模拟这种行为并能够使用正确的 FedAuth cookie 调用 UI 控制器?请不要使用 SharePoint,这与它无关。
我终于能够重现我在 Fiddler 中看到的步骤来模仿浏览器。我会把代码放在这里,希望它能对你们中的一些人有所帮助。它不是很干净,它更像是一种 POC 模式,但它仍然可以提供帮助。请注意,在某些请求中我不得不允许自动重定向,而另一些请求我不得不阻止它。
感谢我的同事 Dominique Pothier,他在这方面帮助了我很多。
//First request to the secured site
var request =
(HttpWebRequest)WebRequest.Create("https://mysite.mycompany.ca/");
request.Method = "GET";
request.UseDefaultCredentials = true;
request.PreAuthenticate = true;
request.AllowAutoRedirect = false;
var httpResponse = (HttpWebResponse)request.GetResponse();
//Redirects to the STS based on the response from the first call, posting the ws-federations infos along
request =
(HttpWebRequest)WebRequest.Create(httpResponse.Headers["Location"]);
request.UseDefaultCredentials = true;
request.PreAuthenticate = true;
request.Host = "sts.mycompany.ca";
request.AllowAutoRedirect = true;
request.UserAgent =
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
var nameValueCollection = new NameValueCollection { { "Cache-Control", "max-age=0" } };
request.Headers.Add(nameValueCollection);
nameValueCollection = new NameValueCollection { { "Upgrade-Insecure-Requests", "1" } };
request.Headers.Add(nameValueCollection);
nameValueCollection = new NameValueCollection { { "Accept-Encoding", "gzip, deflate, sdch" } };
request.Headers.Add(nameValueCollection);
nameValueCollection = new NameValueCollection { { "Accept-Language", "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4" } };
request.Headers.Add(nameValueCollection);
httpResponse = (HttpWebResponse)request.GetResponse();
//Parse the response to get ws-federation infos
var responseStream = new StreamReader(httpResponse.GetResponseStream());
var responseData = responseStream.ReadToEnd();
var xmlReader = XmlReader.Create(new StringReader(responseData));
var wa = "";
var wresult = "";
var wctx = "";
while (xmlReader.Read())
{
if (xmlReader.GetAttribute("name") == "wa")
wa = xmlReader.GetAttribute("value");
if (xmlReader.GetAttribute("name") == "wresult")
wresult = xmlReader.GetAttribute("value");
if (xmlReader.GetAttribute("name") == "wctx")
wctx = xmlReader.GetAttribute("value");
}
httpResponse.Close();
//Redirects to the controller method we want to hit
request =
(HttpWebRequest)WebRequest.Create("https://mysite.mycompany.ca/Home/GetStates");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.AllowAutoRedirect = false;
//Add the cookie container to the response so that we can get the FedAuth cookie after the response
request.CookieContainer = new CookieContainer();
//Add the ws-federation infos from the last http request to the body of the new request
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
if (wa != null)
{
var waEncoded = HttpUtility.UrlEncode(wa);
var wresultEncoded = HttpUtility.UrlEncode(wresult);
var wctxEncoded = HttpUtility.UrlEncode(wctx);
var urlEncoded = "wa=" + waEncoded + "&wresult=" + wresultEncoded + "&wctx=" + wctxEncoded;
streamWriter.Write(urlEncoded);
streamWriter.Flush();
streamWriter.Close();
}
}
request.Referer = httpResponse.ResponseUri.OriginalString;
httpResponse = (HttpWebResponse)request.GetResponse();
var cookieContainer = request.CookieContainer;
//Use the FedAuth cookie that we got from last http call and add it to a new request to the controller and voila !
request =
(HttpWebRequest)WebRequest.Create("https://mysite.mycompany.ca/Home/GetStates");
request.Method = "GET";
nameValueCollection = new NameValueCollection { { "X-Requested-With", "XMLHttpRequest" } };
request.Headers.Add(nameValueCollection);
//Add the FedAuthCookie from last request
request.CookieContainer = cookieContainer;
request.Referer = "https://proacces-dev1.universitas.ca/";
httpResponse = (HttpWebResponse)request.GetResponse();
responseStream = new StreamReader(httpResponse.GetResponseStream());
responseData = responseStream.ReadToEnd();
Console.WriteLine(responseData);
Console.ReadLine();