diff --git a/packages/google-auth-oauthlib/google_auth_oauthlib/flow.py b/packages/google-auth-oauthlib/google_auth_oauthlib/flow.py index eb1ed799223a..e5247d56af07 100644 --- a/packages/google-auth-oauthlib/google_auth_oauthlib/flow.py +++ b/packages/google-auth-oauthlib/google_auth_oauthlib/flow.py @@ -59,6 +59,9 @@ from random import SystemRandom from string import ascii_letters, digits + +import socket +import sys import webbrowser import wsgiref.simple_server import wsgiref.util @@ -432,10 +435,15 @@ def run_local_server( authorization server. """ wsgi_app = _RedirectWSGIApp(success_message) - # Fail fast if the address is occupied + # Fail fast if the address/port is occupied wsgiref.simple_server.WSGIServer.allow_reuse_address = False + # Use _ExclusiveWSGIServer so that other apps cannot bind to the same address/port on Windows. local_server = wsgiref.simple_server.make_server( - bind_addr or host, port, wsgi_app, handler_class=_WSGIRequestHandler + bind_addr or host, + port, + wsgi_app, + server_class=_ExclusiveWSGIServer, + handler_class=_WSGIRequestHandler, ) try: @@ -478,6 +486,21 @@ def run_local_server( return self.credentials +class _ExclusiveWSGIServer(wsgiref.simple_server.WSGIServer): + """Custom WSGIServer. + + Enforces exclusive address binding on Windows. + Setting `WSGIServer.allow_reuse_address` is not enough, since it sets `SO_REUSEADDR` + and not `SO_EXCLUSIVEADDRUSE`. `SO_REUSEADDR` alone allows other processes to bind + to the same address and port on Windows. + """ + + def server_bind(self): + if sys.platform == "win32" and hasattr(socket, "SO_EXCLUSIVEADDRUSE"): + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) + super().server_bind() + + class _WSGIRequestHandler(wsgiref.simple_server.WSGIRequestHandler): """Custom WSGIRequestHandler.