Skip to content

Commit 57c25d8

Browse files
committed
Treat parameter-less HTTP GET as error, while still keeping the welcome page and abort feature
1 parent 3eca00f commit 57c25d8

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

msal/oauth2cli/authcode.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,23 @@ def _printify(text):
111111
class _AuthCodeHandler(BaseHTTPRequestHandler):
112112
def do_GET(self):
113113
qs = parse_qs(urlparse(self.path).query)
114-
if qs:
114+
welcome_param = qs.get('welcome', [None])[0]
115+
error_param = qs.get('error', [None])[0]
116+
if welcome_param == 'true': # Useful in manual e2e tests
117+
self._send_full_response(self.server.welcome_page)
118+
elif error_param == 'abort': # Useful in manual e2e tests
119+
self._send_full_response("Authentication aborted", is_ok=False)
120+
elif qs:
115121
# GET request with auth code or error - reject for security (form_post only)
116122
self._send_full_response(
117123
"response_mode=query is not supported for authentication responses. "
118124
"This application operates in response_mode=form_post mode only.",
119125
is_ok=False)
120126
else:
121-
# Other GET requests - show welcome page
122-
self._send_full_response(self.server.welcome_page)
127+
# IdP may have error scenarios that result in a parameter-less GET request
128+
self._send_full_response(
129+
"Authentication could not be completed. You can close this window and return to the application.",
130+
is_ok=False)
123131
# NOTE: Don't do self.server.shutdown() here. It'll halt the server.
124132

125133
def do_POST(self): # Handle form_post response where auth code is in body
@@ -306,8 +314,8 @@ def _get_auth_response(self, result, auth_uri=None, timeout=None, state=None,
306314
auth_uri_callback=None,
307315
browser_name=None,
308316
):
309-
welcome_uri = "http://localhost:{p}".format(p=self.get_port())
310-
abort_uri = "{loc}?error=abort".format(loc=welcome_uri)
317+
netloc = "http://localhost:{p}".format(p=self.get_port())
318+
abort_uri = "{loc}?error=abort".format(loc=netloc)
311319
logger.debug("Abort by visit %s", abort_uri)
312320

313321
if auth_uri:
@@ -319,12 +327,10 @@ def _get_auth_response(self, result, auth_uri=None, timeout=None, state=None,
319327
"The built-in http server supports HTTP POST only. "
320328
"The auth_uri must be built with response_mode=form_post")
321329

322-
self._server.welcome_page = Template(
323-
welcome_template or
324-
"<a href='$auth_uri'>Sign In</a>, or <a href='$abort_uri'>Abort</a>"
325-
).safe_substitute(auth_uri=auth_uri, abort_uri=abort_uri)
330+
self._server.welcome_page = Template(welcome_template or "").safe_substitute(
331+
auth_uri=auth_uri, abort_uri=abort_uri)
326332
if auth_uri: # Now attempt to open a local browser to visit it
327-
_uri = welcome_uri if welcome_template else auth_uri
333+
_uri = (netloc + "?welcome=true") if welcome_template else auth_uri
328334
logger.info("Open a browser on this device to visit: %s" % _uri)
329335
browser_opened = False
330336
try:
@@ -350,13 +356,14 @@ def _get_auth_response(self, result, auth_uri=None, timeout=None, state=None,
350356
else: # Then it is the auth_uri_callback()'s job to inform the user
351357
auth_uri_callback(_uri)
352358

359+
recommendation = "For your security: Do not share the contents of this page, the address bar, or take screenshots." # From MSRC
353360
self._server.success_template = Template(success_template or
354-
"Authentication complete. You can return to the application. Please close this browser tab.")
361+
"Authentication complete. You can return to the application. Please close this browser tab.\n\n" + recommendation)
355362
self._server.error_template = Template(error_template or
356363
# Do NOT invent new placeholders in this template. Just use standard keys defined in OAuth2 RFC.
357364
# Otherwise there is no obvious canonical way for caller to know what placeholders are supported.
358365
# Besides, we have been using these standard keys for years. Changing now would break backward compatibility.
359-
"Authentication failed. $error: $error_description. ($error_uri)")
366+
"Authentication failed. $error: $error_description. ($error_uri).\n\n" + recommendation)
360367

361368
self._server.timeout = timeout # Otherwise its handle_timeout() won't work
362369
self._server.auth_response = {} # Shared with _AuthCodeHandler
@@ -407,6 +414,8 @@ def __exit__(self, exc_type, exc_val, exc_tb):
407414
)
408415
print(json.dumps(receiver.get_auth_response(
409416
auth_uri=flow["auth_uri"],
417+
welcome_template=
418+
"<a href='$auth_uri'>Sign In</a>, or <a href='$abort_uri'>Abort</a>",
410419
error_template="<html>Oh no. $error</html>",
411420
success_template="Oh yeah. Got $code",
412421
timeout=args.timeout,

0 commit comments

Comments
 (0)