How do I impersonate SAML/SSO from a computer?

Issue

I have a website that I need to access periodically. From the browser it works fine. The site gives me a cookie which expires in 15 minutes. If I go back to the server after an hour, it redirects me to login.microsoft.com which redirects me back to the server.

I need to do the same thing from an unattended computer. Is there a document that discribes what information I need to capture from my destination server and from the the Microsoft IDP server to allow my computer to renew its authentication when the session cookie times out?

Solution

To authenticate with Azure AD IDP I ended up using Puppeteer Sharp (which controls a headless version of Chromium) and the following function (which steps it through its pases) for authentication. The parameter for SSOLogin are as follows:

  • destination – is the REST API that resides behind SSO
  • email – the email address used to authenticate
  • password – the password associated with the email address
  • selector – an element selector that is present in the API
  • cookieParams – the cookies sent by the API and the IDP

Initially there are no cookies. However, SSOLogin returns the current set of cookies. If the cookies for the API have not expired login is quick and easy. If the IDP cookies have not expired you get redirected back to the API. If the cookies on the IDP have expired then you get to login using the email address and password.

In any case you can extract the cookies from the API and use them to make the call.

Nuget packages used:

  • 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);
     }
    

Answered By – JSWilson

Answer Checked By – Senaida (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.