Skip to content

Commit

Permalink
Fix azure oauth issues (#7587)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcSkovMadsen authored Jan 13, 2025
1 parent b4ab22b commit a4b9a87
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 3 deletions.
12 changes: 10 additions & 2 deletions panel/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def decode_response_body(response):
body = codecs.decode(response.body, 'ascii')
except Exception:
body = codecs.decode(response.body, 'utf-8')
body = re.sub("\'", '\\"', body)
body = re.sub('"', '\"', body)
body = re.sub("'", '"', body)
body = json.loads(body)
Expand Down Expand Up @@ -450,10 +451,17 @@ def _raise_error(self, response, body=None, status=400):
log.warning(f"{provider} OAuth provider failed to fully "
f"authenticate returning the following response:"
f"{body}.")
if hasattr(body, "get"):
log_message = body.get('error_description', str(body))
reason = body.get('error', 'Unknown error')
else:
log_message = str(response)
reason = 'Unknown Error'

raise HTTPError(
status,
body.get('error_description', str(body)),
reason=body.get('error', 'Unknown error')
log_message=log_message,
reason=reason
)

def write_error(self, status_code, **kwargs):
Expand Down
2 changes: 1 addition & 1 deletion panel/command/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def main(args: list[str] | None = None):
try:
ret = parsed_args.invoke(parsed_args)
except Exception as e:
if config.dev:
if config.autoreload:
raise e
die("ERROR: " + str(e))
else:
Expand Down
63 changes: 63 additions & 0 deletions panel/tests/test_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
This module contains tests for handling OAuth login and response decoding
using the Tornado HTTP client and Panel's OAuthLoginHandler.
"""

from unittest.mock import Mock, patch

import pytest

from tornado.httpclient import HTTPRequest, HTTPResponse
from tornado.web import HTTPError

from panel.auth import OAuthLoginHandler, decode_response_body


def _create_mock_response(body, code=401):
"""
Create a mock HTTPResponse object with the specified body and status code.
Parameters
----------
body : bytes
The body content of the mock response.
code : int, optional
The HTTP status code of the mock response (default is 401).
Returns
-------
Mock
A mock HTTPResponse object with the specified attributes.
"""
mock_request = Mock(spec=HTTPRequest)
mock_response = Mock(spec=HTTPResponse)
mock_response.body = body
mock_response.request = mock_request
mock_response.code = code
return mock_response

def test_decode_invalid_response_body():
"""
Test the decode_response_body function with an invalid JSON response body.
Ensures that the function can handle and correct invalid JSON containing
single quotes, which are not valid in JSON strings.
"""
# The body below from azure contains \' which is not valid json.
body = b'{"error_description":"... for a secret added to app \'some-value\'."}'
invalid_response = _create_mock_response(body)
result = decode_response_body(invalid_response)
assert result == {'error_description': '... for a secret added to app "some-value".'}

def test_raise_error():
"""
Test the _raise_error method of OAuthLoginHandler with an invalid JSON response.
Mocks the OAuthLoginHandler to bypass initialization and verifies that
an HTTPError is raised when the response contains invalid JSON.
"""
response = _create_mock_response(b'{"invalid_json": "missing_end_quote}')
with patch.object(OAuthLoginHandler, '__init__', lambda self, *args, **kwargs: None):
handler = OAuthLoginHandler()
with pytest.raises(HTTPError):
handler._raise_error(response=response, body=None, status=401)

0 comments on commit a4b9a87

Please sign in to comment.