如何从计算机上模拟 SAML/SSO?
How do I impersonate SAML/SSO from a computer?
我有一个需要定期访问的网站。从浏览器它工作正常。该网站给了我一个 15 分钟后过期的 cookie。如果我在一小时后返回服务器,它会将我重定向到 login.microsoft.com,然后将我重定向回服务器。
我需要在无人看管的计算机上做同样的事情。是否有文档描述我需要从目标服务器和 Microsoft IDP 服务器捕获哪些信息,以允许我的计算机在会话 cookie 超时时更新其身份验证?
为了使用 Azure AD IDP 进行身份验证,我最终使用 Puppeteer Sharp(控制 Chromium 的无头版本)和以下函数(逐步完成其步骤)进行身份验证。 SSOLogin的参数如下:
- 目的地 - 是位于 SSO
后面的 REST API
- email - 用于验证的电子邮件地址
- 密码 - 与电子邮件地址关联的密码
- 选择器 - API
中存在的元素选择器
- cookieParams - API 和 IDP
发送的 cookie
最初没有cookie。但是,SSOLogin returns 当前的 cookie 集。如果 API 的 cookies 没有过期,登录是快速和容易的。如果 IDP cookie 尚未过期,您将被重定向回 API。如果 IDP 上的 cookie 已过期,那么您可以使用电子邮件地址和密码登录。
在任何情况下,您都可以从 API 中提取 cookie 并使用它们进行调用。
使用的 Nuget 包:
Microsoft.AspNet.WebApi.Client (5.2.7)
PuppeteerSharp (5.0.0)
System.Net.Http.Json (5.0.0)
public static async Task<CookieParam[]> SSOLogin(CookieParam[] cookieParams, string destination, string email, string password, string selector)
{
var options = new LaunchOptions { Headless = true }; // Set to false to watch browser step through activities
var selectorOption = new WaitForSelectorOptions { Visible = true, Timeout = 10000 };
await new BrowserFetcher().DownloadAsync(); // Only needed the first time through
using var browser = await Puppeteer.LaunchAsync(options);
using var page = await browser.NewPageAsync();
await page.SetCookieAsync(cookieParams);
await page.GoToAsync(destination);
try
{
await page.WaitForSelectorAsync($"{selector}, input[name='loginfmt']", selectorOption);
}
catch (Exception e)
{
Console.WriteLine($"First page error: {e.Message}");
}
var url = page.Url;
if (url.StartsWith("https://login.microsoftonline.com/"))
{
if (await page.QuerySelectorAsync($"div[data-test-id='{email}']") != null)
{
await page.ClickAsync($"div[data-test-id='{email}']");
}
else
{
await page.WaitForSelectorAsync("input[name='loginfmt']:not(.moveOffScreen)", selectorOption);
await page.FocusAsync("input[name='loginfmt']");
await page.Keyboard.TypeAsync(email);
await page.WaitForSelectorAsync("input[type=submit]", selectorOption);
await page.ClickAsync("input[type=submit]");
}
await page.WaitForSelectorAsync("input[type=password]:not(.moveOffScreen)", selectorOption);
await page.FocusAsync("input[type=password]");
await page.Keyboard.TypeAsync(password);
await page.WaitForSelectorAsync("input[type=submit]", selectorOption);
await page.ClickAsync("input[type=submit]");
await page.WaitForSelectorAsync("input[name='DontShowAgain']:not(.moveOffScreen)", selectorOption);
await page.ClickAsync("input[name='DontShowAgain']");
await page.WaitForSelectorAsync("input[type=submit]", selectorOption);
await page.ClickAsync("input[type=submit]");
await page.WaitForSelectorAsync(selector, selectorOption);
}
return await page.GetCookiesAsync("https://login.microsoftonline.com/", destination);
}
我有一个需要定期访问的网站。从浏览器它工作正常。该网站给了我一个 15 分钟后过期的 cookie。如果我在一小时后返回服务器,它会将我重定向到 login.microsoft.com,然后将我重定向回服务器。
我需要在无人看管的计算机上做同样的事情。是否有文档描述我需要从目标服务器和 Microsoft IDP 服务器捕获哪些信息,以允许我的计算机在会话 cookie 超时时更新其身份验证?
为了使用 Azure AD IDP 进行身份验证,我最终使用 Puppeteer Sharp(控制 Chromium 的无头版本)和以下函数(逐步完成其步骤)进行身份验证。 SSOLogin的参数如下:
- 目的地 - 是位于 SSO 后面的 REST API
- email - 用于验证的电子邮件地址
- 密码 - 与电子邮件地址关联的密码
- 选择器 - API 中存在的元素选择器
- cookieParams - API 和 IDP 发送的 cookie
最初没有cookie。但是,SSOLogin returns 当前的 cookie 集。如果 API 的 cookies 没有过期,登录是快速和容易的。如果 IDP cookie 尚未过期,您将被重定向回 API。如果 IDP 上的 cookie 已过期,那么您可以使用电子邮件地址和密码登录。
在任何情况下,您都可以从 API 中提取 cookie 并使用它们进行调用。
使用的 Nuget 包:
Microsoft.AspNet.WebApi.Client (5.2.7)
PuppeteerSharp (5.0.0)
System.Net.Http.Json (5.0.0)
public static async Task<CookieParam[]> SSOLogin(CookieParam[] cookieParams, string destination, string email, string password, string selector) { var options = new LaunchOptions { Headless = true }; // Set to false to watch browser step through activities var selectorOption = new WaitForSelectorOptions { Visible = true, Timeout = 10000 }; await new BrowserFetcher().DownloadAsync(); // Only needed the first time through using var browser = await Puppeteer.LaunchAsync(options); using var page = await browser.NewPageAsync(); await page.SetCookieAsync(cookieParams); await page.GoToAsync(destination); try { await page.WaitForSelectorAsync($"{selector}, input[name='loginfmt']", selectorOption); } catch (Exception e) { Console.WriteLine($"First page error: {e.Message}"); } var url = page.Url; if (url.StartsWith("https://login.microsoftonline.com/")) { if (await page.QuerySelectorAsync($"div[data-test-id='{email}']") != null) { await page.ClickAsync($"div[data-test-id='{email}']"); } else { await page.WaitForSelectorAsync("input[name='loginfmt']:not(.moveOffScreen)", selectorOption); await page.FocusAsync("input[name='loginfmt']"); await page.Keyboard.TypeAsync(email); await page.WaitForSelectorAsync("input[type=submit]", selectorOption); await page.ClickAsync("input[type=submit]"); } await page.WaitForSelectorAsync("input[type=password]:not(.moveOffScreen)", selectorOption); await page.FocusAsync("input[type=password]"); await page.Keyboard.TypeAsync(password); await page.WaitForSelectorAsync("input[type=submit]", selectorOption); await page.ClickAsync("input[type=submit]"); await page.WaitForSelectorAsync("input[name='DontShowAgain']:not(.moveOffScreen)", selectorOption); await page.ClickAsync("input[name='DontShowAgain']"); await page.WaitForSelectorAsync("input[type=submit]", selectorOption); await page.ClickAsync("input[type=submit]"); await page.WaitForSelectorAsync(selector, selectorOption); } return await page.GetCookiesAsync("https://login.microsoftonline.com/", destination); }