AzureAD / microsoft-authentication-library-for-python

Microsoft Authentication Library (MSAL) for Python makes it easy to authenticate to Microsoft Entra ID. General docs are available here https://learn.microsoft.com/entra/msal/python/ Stable APIs are documented here https://msal-python.readthedocs.io. Questions can be asked on www.stackoverflow.com with tag "msal" + "python".
https://stackoverflow.com/questions/tagged/azure-ad-msal+python
Other
788 stars 194 forks source link

`acquire_token_interactive` can't be stopped by Ctrl+C #393

Closed jiasli closed 2 years ago

jiasli commented 3 years ago

Describe the bug

PublicClientApplication.acquire_token_interactive can't be stopped by Ctrl+C.

To Reproduce

  1. Call PublicClientApplication.acquire_token_interactive
  2. Press Ctrl+C

Expected behavior

MSAL should respond to KeyboardInterrupt.

What you see instead

The terminal hangs. The only way to stop it is Ctrl+Break (https://stackoverflow.com/questions/1364173/stopping-python-using-ctrlc).

The MSAL Python version you are using

1.13.0

Additional context

Azure CLI runs HTTPServer on a daemon thread so that Ctrl+C can stop the main thread which is time.sleeping: https://github.com/Azure/azure-cli/blob/a4d84cc6e7fb6bd741753cb6a52410d0397c56c3/src/azure-cli-core/azure/cli/core/_profile.py#L1383-L1397

Another possible solution is to call HTTPServer.serve_forever. This is the approach of http.server when we run

python -m http.server 8000

Per socketserver.BaseServer.serve_forever, it internally resumes control to the main thread every poll_interval seconds so that KeyboardInterrupt can be handled.

jiasli commented 3 years ago

Once Ctrl+C is pressed, the daemon thread approach used by Azure CLI terminates the command immediately, while the serve_forever approach requires several seconds for the main thread to respond.

For the serve_forever approach, I wrote a sample test script modified from https://docs.python.org/3/library/selectors.html#examples

import selectors
import socket

sel = selectors.DefaultSelector()

sock = socket.socket()
sock.bind(('localhost', 1234))
sock.listen(100)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ)

while True:
    events = sel.select(5)
    if events:
        print("received!")

Run the script and press Ctrl+C, notice KeyboardInterrupt is handled 5 seconds later.

rayluo commented 3 years ago

Thanks, Jiashuo, for bringing this to our attention, and also providing extra effort on presenting alternatives. We are working on this.