如何从计算机上模拟 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);
     }