SSO Authentication with Selenium

Adrian Macal
5 min readApr 7, 2023

--

Photo by FLY:D on Unsplash

Can Selenium simplify your SSO authentication process? Explore the possibilities for a more efficient development experience!

Single Sign-On provides a unique experience when working with multiple separate systems. It allows you to use the same credentials across all platforms. To enhance security, SSO is often supported by Multi-Factor Authentication. SSO is designed primarily for humans, who need a safe and convenient way to access multiple websites, and it is not intended for automation.

This blog post explains how to use Selenium, a popular library for running Chromium in headless mode, to perform SSO authentication backed by Auth0, Microsoft and Duo. It covers the basic features of Selenium and focuses on flexible design that can support multiple SSO providers.

Context

Suppose you have multiple services protected by SSO, and you would like to automate some aspects of the development process (we’re not considering production here). The authentication process may look like one of the flows below. To access Databricks, Snowflake, or AKeyless, you need to go through the same authentication steps.

For instance, you might want to automate obtaining token for AKeyless CLI by opening a URL, returned by CLI, and automatically completing the authorization steps. Then you could perform development tasks using already configured session. AKeyless can be somewhat annoying, because it returns a token valid for only one hour.

Implementation: Core

I started by defining the ViewTerminal class to separate user input prompts, like email and password, from the rest of the code. I chose Python Prompt Toolkit 3.0 for a seamless integration.

Next, I created the ViewContext class, which encapsulates common concepts like accessing the terminal and the driver, as well as providing some reusable code to wait for multiple conditions, such as finding an XPath node, URL changes, or network idling. Later, an instance of this class is often passed between various components.

I then defined three classes serving as protocols that describe the signatures of core functional components. The entire solution is based on the idea that multiple probers and interceptors handle the process. The ViewProber is responsible for identifying if it can handle the current view and optionally returns an interceptor. The ViewInterceptor handles the current view. The last one, the ViewCallback, verifies if the goal is reached and the entire SSO chain was successfully completed.

Finally, I created functional decorators to catch Selenium exceptions, which may occur during probing or intercepting. Both methods comply with the wrapped signatures.

Implementation: Probers and Interceptors

I decided to start from the beginning. I took Databricks as starting point. It looks like the “Single Sign On” button has to be identified and clicked to complete the stage.

It redirects me to Auth0 authentication platform. It depends on the workspace. Once I see it I know I need to type my corporate email and click the “Log In” button.

Auth0 feels quite suspicious because I used totally fresh session without any cookies. It leads to redirecting my to Microsoft to verify my password associated with the email. I have to provide the password and click the “Sign In” button in the form.

The final step is MFA. Duo offers it for companies and in my case I need to find a device which supports sending push messages to my phone. It is more complicated because it requires switching to IFrame, but still Selenium supports is perfectly.

When email and password were provided as expected and push message was handled within 30 seconds, I can see my Databricks’ welcome page.

Implementation: Final

The final step is to combine all previously shared code into one callable function, which does anything required to successfully complete any flow. The single_sign_on function takes the Chrome driver and an optional callback to determine if the flow successfully completed or not. It returns true if the flow succeeded, false if something failed and none if the flow couldn’t be completed. The function also persists a screenshot each iteration. I attached them in previous paragraphs.

The function is called from click handler, which can be called directly from console. It completes entire flow and outputs True or False. Additionally, it preserves the Chrome profile in the current directory to possibly avoid complete flow next time when it is called.

Summary

The shared code does what is expected and as always it could be improved. It could handle for example more edge cases or give the user more output. I don’t mention I didn’t do any unit testing, but the code is possibly ready to be unit tested.

The intention of this post is not to encourage you to do any automation on production or development which may lead to compromising your security. It demonstrates that some automation is possible even if some human interaction is required. It also opens the door for some cases when you may save your or others precious time by avoiding some manual clicks. Remember, you are in full charge what is happening with your precious credentials.

Is it worth to try out? It’s up to you to decide! In case you are interested in the code, you can find it here: https://github.com/amacal/learning-python/tree/sso-selenium-automation

--

--

Adrian Macal
Adrian Macal

Written by Adrian Macal

Software Developer, Data Engineer with solid knowledge of Business Intelligence. Passionate about programming.

No responses yet