diff --git a/CHANGELOG.md b/CHANGELOG.md index 30de936..06b2d01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Adding explicit support for Python `3.12`. - Publicly expose `requests_auth.SupportMultiAuth`, allowing multiple authentication support for every `requests` authentication class that exists. - Publicly expose `requests_auth.TokenMemoryCache`, allowing to create custom Oauth2 token cache based on this default implementation. +- You can now provide your own HTML success (`success_html`) and failure (`failure_html`) display via the new `OAuth2.display` shared setting. Refer to documentation for more details. - Thanks to the new `redirect_uri_domain` parameter on Authorization code (with and without PKCE) and Implicit flows, you can now provide the [FQDN](https://en.wikipedia.org/wiki/Fully_qualified_domain_name) to use in the `redirect_uri` when `localhost` (the default) is not allowed. - `requests_auth.WakaTimeAuthorizationCode` handling access to the [WakaTime API](https://wakatime.com/developers). @@ -19,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `requests_auth.JsonTokenFileCache` does not expose `tokens_path` or `last_save_time` attributes anymore and is also allowing `pathlib.Path` instances as cache location. - `requests_auth.TokenMemoryCache` does not expose `forbid_concurrent_cache_access` or `forbid_concurrent_missing_token_function_call` attributes anymore. - Browser display settings have been moved to a shared setting, see documentation for more information on `requests_auth.OAuth2.display`. + The failure page will be displayed for 10 seconds by default instead of 5 seconds previously. As a result the following classes no longer expose `success_display_time` and `failure_display_time` parameters. - `requests_auth.OAuth2AuthorizationCode`. - `requests_auth.OktaAuthorizationCode`. @@ -30,6 +32,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `requests_auth.AzureActiveDirectoryImplicitIdToken`. - `requests_auth.OktaImplicit`. - `requests_auth.OktaImplicitIdToken`. +- The authentication success and failure displayed in the browser were revamped to be more user-friendly. `requests_auth.testing` was modified to accommodate this change: + - `tab.assert_success` `expected_message` parameter was removed. + - `tab.assert_failure` `expected_message` parameter should not be prefixed with `Unable to properly perform authentication: ` anymore and `\n` in the message should be replaced with `
`. ### Fixed - Type information is now provided following [PEP 561](https://www.python.org/dev/peps/pep-0561/). diff --git a/README.md b/README.md index a9b1881..af4e947 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Build status Coverage Code style: black -Number of tests +Number of tests Number of downloads

@@ -703,7 +703,9 @@ The following parameters can be provided to `DisplaySettings`: | Name | Description | Default value | |:-----------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------| | `success_display_time` | In case a code or token is successfully received, this is the maximum amount of milliseconds the success page will be displayed in your browser. | 1 | -| `failure_display_time` | In case received code or token is not valid, this is the maximum amount of milliseconds the failure page will be displayed in your browser. | 5_000 | +| `success_html` | In case a code or token is successfully received, this is the success page that will be displayed in your browser. `{display_time}` is expected in this content. | | +| `failure_display_time` | In case received code or token is not valid, this is the maximum amount of milliseconds the failure page will be displayed in your browser. | 10_000 | +| `failure_html` | In case received code or token is not valid, this is the failure page that will be displayed in your browser. `{information}` and `{display_time}` are expected in this content. | | ## API key in header @@ -911,9 +913,7 @@ def test_something(browser_mock: BrowserMock): # perform code using authentication - tab.assert_success( - "You are now authenticated on 1234 You may close this tab." - ) + tab.assert_success() ``` ## Endorsements diff --git a/requests_auth/_oauth2/authentication_responses_server.py b/requests_auth/_oauth2/authentication_responses_server.py index 0240d21..1a49526 100644 --- a/requests_auth/_oauth2/authentication_responses_server.py +++ b/requests_auth/_oauth2/authentication_responses_server.py @@ -36,7 +36,10 @@ def do_GET(self): self.server.request_error = e logger.exception("Unable to properly perform authentication.") self.send_html( - self.error_page(f"Unable to properly perform authentication: {e}") + OAuth2.display.failure_html.format( + display_time=OAuth2.display.failure_display_time, + information=str(e).replace("\n", "
"), + ) ) def do_POST(self): @@ -48,7 +51,10 @@ def do_POST(self): self.server.request_error = e logger.exception("Unable to properly perform authentication.") self.send_html( - self.error_page(f"Unable to properly perform authentication: {e}") + OAuth2.display.failure_html.format( + display_time=OAuth2.display.failure_display_time, + information=str(e).replace("\n", "
"), + ) ) def _parse_grant(self, arguments: dict): @@ -67,15 +73,15 @@ def _parse_grant(self, arguments: dict): state = states[0] self.server.grant = state, grant self.send_html( - self.success_page( - f"You are now authenticated on {state}. You may close this tab." + OAuth2.display.success_html.format( + display_time=OAuth2.display.success_display_time ) ) def _get_form(self): content_length = int(self.headers.get("Content-Length", 0)) body_str = self.rfile.read(content_length).decode("utf-8") - return parse_qs(body_str, keep_blank_values=1) + return parse_qs(body_str, keep_blank_values=True) def _get_params(self): return parse_qs(urlparse(self.path).query) @@ -87,28 +93,6 @@ def send_html(self, html_content: str): self.wfile.write(str.encode(html_content)) logger.debug("HTML content sent to client.") - def success_page(self, text: str): - return f""" -
{text}
- """ - - def error_page(self, text: str): - return f""" -
{text}
- """ - def fragment_redirect_page(self): """Return a page with JS that calls back the server on the url original url: scheme://FQDN/path#fragment @@ -180,7 +164,7 @@ def request_new_grant(grant_details: GrantDetails) -> (str, str): :raises InvalidGrantRequest: If the request was invalid. :raises TimeoutOccurred: If not retrieved within timeout. :raises GrantNotProvided: If grant is not provided in response (but no error occurred). - :raises StateNotProvided: If state if not provided in addition to the grant. + :raises StateNotProvided: If state is not provided in addition to the grant. """ logger.debug(f"Requesting new {grant_details.name}...") diff --git a/requests_auth/_oauth2/browser.py b/requests_auth/_oauth2/browser.py index dba045c..2ee4c8d 100644 --- a/requests_auth/_oauth2/browser.py +++ b/requests_auth/_oauth2/browser.py @@ -31,22 +31,122 @@ def __init__(self, kwargs): class DisplaySettings: + _default_template = """ + + + {title} + + + +
+

{title}

+

{information}

+
+
+ Documentation + Latest changes +
+ +""" + _default_success = ( + _default_template.replace("{title}", "Authentication success") + .replace("{color}", "#32cd32") + .replace("{background_color}", "#f0fff0") + .replace("{information}", "You can close this tab") + ) + _default_failure = ( + _default_template.replace("{title}", "Authentication failed") + .replace("{color}", "#dc143c") + .replace("{background_color}", "#fffafa") + ) + def __init__( self, *, success_display_time: int = 1, - failure_display_time: int = 5_000, + success_html: str = None, + failure_display_time: int = 10_000, + failure_html: str = None, ): """ :param success_display_time: In case a code/token is successfully received, this is the maximum amount of milliseconds the success page will be displayed in your browser. Display the page for 1 millisecond by default. + :param success_html: In case a code or token is successfully received, + this is the success page that will be displayed in your browser. + `{display_time}` is expected in this content. :param failure_display_time: In case received code/token is not valid, this is the maximum amount of milliseconds the failure page will be displayed in your browser. - Display the page for 5 seconds by default. + Display the page for 10 seconds by default. + :param failure_html: In case received code or token is not valid, + this is the failure page that will be displayed in your browser. + `{information}` and `{display_time}` are expected in this content. """ # Time is expressed in milliseconds self.success_display_time = success_display_time + self.success_html = success_html or self._default_success # Time is expressed in milliseconds self.failure_display_time = failure_display_time + self.failure_html = failure_html or self._default_failure diff --git a/requests_auth/testing.py b/requests_auth/testing.py index 1e8fe1e..ce70470 100644 --- a/requests_auth/testing.py +++ b/requests_auth/testing.py @@ -34,10 +34,177 @@ class Tab(threading.Thread): * assert the content sent to the browser """ - def __init__(self, reply_url: str, data: str): + def __init__( + self, + reply_url: str, + data: str, + displayed_html: Optional[str] = None, + ): self.reply_url = reply_url self.data = data.encode() if data is not None else None self.checked = False + self.success_html = ( + displayed_html + or """ + + + Authentication success + + + +
+

Authentication success

+

You can close this tab

+
+
+ Documentation + Latest changes +
+ +""" + ) + self.failure_html = ( + displayed_html + or """ + + + Authentication failed + + + +
+

Authentication failed

+

{information}

+
+
+ Documentation + Latest changes +
+ +""" + ) super().__init__() def run(self) -> None: @@ -50,7 +217,7 @@ def run(self) -> None: # Simulate a browser tab token redirect to the reply URL self.content = self._simulate_redirect().decode() - def _request_favicon(self): + def _request_favicon(self) -> None: scheme, netloc, *_ = urlsplit(self.reply_url) favicon_response = urllib.request.urlopen(f"{scheme}://{netloc}/favicon.ico") assert favicon_response.read() == b"Favicon is not provided." @@ -76,19 +243,15 @@ def _simulate_requests_auth_redirect(self) -> bytes: ) return urllib.request.urlopen(reply_url, data=self.data).read() - def assert_success(self, expected_message: str, timeout: int = 1): + def assert_success(self, timeout: int = 1) -> None: self.join() - assert ( - self.content - == f"\n
{expected_message}
\n " - ) + assert self.content == self.success_html.format(display_time=timeout) self.checked = True - def assert_failure(self, expected_message: str, timeout: int = 5000): + def assert_failure(self, expected_message: str, timeout: int = 10_000) -> None: self.join() - assert ( - self.content - == f"\n
{expected_message}
\n " + assert self.content == self.failure_html.format( + display_time=timeout, information=expected_message ) self.checked = True @@ -97,7 +260,7 @@ class BrowserMock: def __init__(self): self.tabs: Dict[str, Tab] = {} - def open(self, url: str, new: int): + def open(self, url: str, new: int) -> bool: assert new == 1 assert url in self.tabs, f"Browser call on {url} was not mocked." # Simulate a browser by sending the response in another thread @@ -105,18 +268,23 @@ def open(self, url: str, new: int): return True def add_response( - self, opened_url: str, reply_url: Optional[str], data: str = None + self, + opened_url: str, + reply_url: Optional[str], + data: Optional[str] = None, + displayed_html: Optional[str] = None, ) -> Tab: """ :param opened_url: URL opened by requests_auth :param reply_url: The URL to send a response to, None to simulate the fact that there is no redirect. :param data: Body of the POST response to be sent. None to send a GET request. + :param displayed_html: Expected success/failure page. """ - tab = Tab(reply_url, data) + tab = Tab(reply_url, data, displayed_html) self.tabs[opened_url] = tab return tab - def assert_checked(self): + def assert_checked(self) -> None: for url, tab in self.tabs.items(): tab.join() assert tab.checked, f"Response received on {url} was not checked properly." diff --git a/tests/features/multi_auth/test_add_operator.py b/tests/features/multi_auth/test_add_operator.py index 9605b8f..8a4f6bc 100644 --- a/tests/features/multi_auth/test_add_operator.py +++ b/tests/features/multi_auth/test_add_operator.py @@ -360,9 +360,7 @@ def test_oauth2_authorization_code_and_api_key_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_and_multiple_authentication_can_be_combined( @@ -406,9 +404,7 @@ def test_oauth2_authorization_code_and_multiple_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_and_api_key_authentication_can_be_combined( @@ -451,9 +447,7 @@ def test_oauth2_pkce_and_api_key_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_and_multiple_authentication_can_be_combined( @@ -500,9 +494,7 @@ def test_oauth2_pkce_and_multiple_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_and_api_key_authentication_can_be_combined( @@ -535,9 +527,7 @@ def test_oauth2_implicit_and_api_key_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_and_multiple_authentication_can_be_combined( @@ -574,6 +564,4 @@ def test_oauth2_implicit_and_multiple_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() diff --git a/tests/features/multi_auth/test_and_operator.py b/tests/features/multi_auth/test_and_operator.py index b08a78d..4abe2af 100644 --- a/tests/features/multi_auth/test_and_operator.py +++ b/tests/features/multi_auth/test_and_operator.py @@ -360,9 +360,7 @@ def test_oauth2_authorization_code_and_api_key_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_and_multiple_authentication_can_be_combined( @@ -406,9 +404,7 @@ def test_oauth2_authorization_code_and_multiple_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_and_api_key_authentication_can_be_combined( @@ -451,9 +447,7 @@ def test_oauth2_pkce_and_api_key_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_and_multiple_authentication_can_be_combined( @@ -500,9 +494,7 @@ def test_oauth2_pkce_and_multiple_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_and_api_key_authentication_can_be_combined( @@ -535,9 +527,7 @@ def test_oauth2_implicit_and_api_key_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_and_multiple_authentication_can_be_combined( @@ -574,6 +564,4 @@ def test_oauth2_implicit_and_multiple_authentication_can_be_combined( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() diff --git a/tests/oauth2/authorization_code/test_oauth2_authorization_code.py b/tests/oauth2/authorization_code/test_oauth2_authorization_code.py index f54e962..60012d6 100644 --- a/tests/oauth2/authorization_code/test_oauth2_authorization_code.py +++ b/tests/oauth2/authorization_code/test_oauth2_authorization_code.py @@ -47,9 +47,7 @@ def test_oauth2_authorization_code_flow_uses_provided_session( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_uses_redirect_uri_domain( @@ -91,8 +89,73 @@ def test_oauth2_authorization_code_flow_uses_redirect_uri_domain( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." + tab.assert_success() + + +def test_oauth2_authorization_code_flow_uses_custom_success( + token_cache, responses: RequestsMock, browser_mock: BrowserMock +): + auth = requests_auth.OAuth2AuthorizationCode( + "http://provide_code", + "http://provide_access_token", + ) + requests_auth.OAuth2.display.success_html = ( + "
SUCCESS: {display_time}
" + ) + tab = browser_mock.add_response( + opened_url="http://provide_code?response_type=code&state=163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#code=SplxlOBeZQQYbYS6WxSbIA&state=163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de", + displayed_html="
SUCCESS: {display_time}
", + ) + responses.post( + "http://provide_access_token", + json={ + "access_token": "2YotnFZFEjr1zCsicMWpAA", + "token_type": "example", + "expires_in": 3600, + "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter": "example_value", + }, + match=[ + urlencoded_params_matcher( + { + "grant_type": "authorization_code", + "redirect_uri": "http://localhost:5000/", + "response_type": "code", + "code": "SplxlOBeZQQYbYS6WxSbIA", + } + ), + ], + ) + responses.get( + "http://authorized_only", + match=[header_matcher({"Authorization": "Bearer 2YotnFZFEjr1zCsicMWpAA"})], + ) + + requests.get("http://authorized_only", auth=auth) + + tab.assert_success() + + +def test_oauth2_authorization_code_flow_uses_custom_failure( + token_cache, browser_mock: BrowserMock +): + auth = requests_auth.OAuth2AuthorizationCode( + "http://provide_code", + "http://provide_access_token", + ) + requests_auth.OAuth2.display.failure_html = "FAILURE: {display_time}\n{information}" + tab = browser_mock.add_response( + opened_url="http://provide_code?response_type=code&state=163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#error=invalid_request", + displayed_html="FAILURE: {display_time}\n{information}", + ) + + with pytest.raises(requests_auth.InvalidGrantRequest): + requests.get("http://authorized_only", auth=auth) + + tab.assert_failure( + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -133,9 +196,7 @@ def test_oauth2_authorization_code_flow_get_code_is_sent_in_authorization_header requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_token_is_expired_after_30_seconds_by_default( @@ -182,9 +243,7 @@ def test_oauth2_authorization_code_flow_token_is_expired_after_30_seconds_by_def requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_client_credentials_flow_token_custom_expiry( @@ -244,9 +303,7 @@ def test_refresh_token(token_cache, responses: RequestsMock, browser_mock: Brows requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() # response for refresh token grant responses.post( @@ -313,9 +370,7 @@ def test_refresh_token_invalid( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() # response for refresh token grant responses.post( "http://provide_access_token", @@ -346,9 +401,7 @@ def test_refresh_token_invalid( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_refresh_token_access_token_not_expired( @@ -388,9 +441,7 @@ def test_refresh_token_access_token_not_expired( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() # expect Bearer token to remain the same responses.get( @@ -427,9 +478,7 @@ def test_empty_token_is_invalid( str(exception_info.value) == "access_token not provided within {'access_token': '', 'token_type': 'example', 'expires_in': 3600, 'refresh_token': 'tGzv3JOkF0XG5Qx2TlKWIA', 'example_parameter': 'example_value'}." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_no_json( @@ -446,9 +495,7 @@ def test_with_invalid_grant_request_no_json( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "failure" - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error( @@ -475,9 +522,7 @@ def test_with_invalid_grant_request_invalid_request_error( "includes multiple credentials, utilizes more than one mechanism for " "authenticating the client, or is otherwise malformed." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description( @@ -498,9 +543,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc of the error" - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri( @@ -528,9 +571,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on http://test_url" ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri_and_other_fields( @@ -559,9 +600,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == "invalid_request: desc of the error\nMore information can be found on http://test_url\nAdditional information: {'other': 'other info'}" ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_without_error( @@ -582,9 +621,7 @@ def test_with_invalid_grant_request_without_error( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "{'other': 'other info'}" - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_client_error( @@ -615,9 +652,7 @@ def test_with_invalid_grant_request_invalid_client_error( 'code and include the "WWW-Authenticate" response header field matching the ' "authentication scheme used by the client." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_grant_error( @@ -644,9 +679,7 @@ def test_with_invalid_grant_request_invalid_grant_error( "does not match the redirection URI used in the authorization request, or was " "issued to another client." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unauthorized_client_error( @@ -671,9 +704,7 @@ def test_with_invalid_grant_request_unauthorized_client_error( == "unauthorized_client: The authenticated client is not authorized to use this " "authorization grant type." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unsupported_grant_type_error( @@ -698,9 +729,7 @@ def test_with_invalid_grant_request_unsupported_grant_type_error( == "unsupported_grant_type: The authorization grant type is not supported by the " "authorization server." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_scope_error( @@ -725,9 +754,7 @@ def test_with_invalid_grant_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, malformed, or " "exceeds the scope granted by the resource owner." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_token_request_invalid_request_error( @@ -747,7 +774,7 @@ def test_with_invalid_token_request_invalid_request_error( == "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -764,9 +791,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc" - tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc" - ) + tab.assert_failure("invalid_request: desc") def test_with_invalid_token_request_invalid_request_error_and_error_description_and_uri( @@ -786,7 +811,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url" + "invalid_request: desc
More information can be found on http://test_url" ) @@ -807,7 +832,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" + "invalid_request: desc
More information can be found on http://test_url
Additional information: {'other': ['test']}" ) @@ -828,7 +853,7 @@ def test_with_invalid_token_request_unauthorized_client_error( == "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." + "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) @@ -849,7 +874,7 @@ def test_with_invalid_token_request_access_denied_error( == "access_denied: The resource owner or authorization server denied the request." ) tab.assert_failure( - "Unable to properly perform authentication: access_denied: The resource owner or authorization server denied the request." + "access_denied: The resource owner or authorization server denied the request." ) @@ -870,7 +895,7 @@ def test_with_invalid_token_request_unsupported_response_type_error( == "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." + "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) @@ -891,7 +916,7 @@ def test_with_invalid_token_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, or malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_scope: The requested scope is invalid, unknown, or malformed." + "invalid_scope: The requested scope is invalid, unknown, or malformed." ) @@ -912,7 +937,7 @@ def test_with_invalid_token_request_server_error_error( == "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" + "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -933,7 +958,7 @@ def test_with_invalid_token_request_temporarily_unavailable_error( == "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" + "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -974,9 +999,7 @@ def test_nonce_is_sent_if_provided_in_authorization_url( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_response_type_can_be_provided_in_url( @@ -1017,9 +1040,7 @@ def test_response_type_can_be_provided_in_url( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 49b67a19e70f692c3fc09dd124e5782b41a86f4f4931e1cc938ccbb466eecf1b730edb9eb01e42005de77ce3dd5a016418f8e780f30c4477d71102fe03e39e62. You may close this tab." - ) + tab.assert_success() def test_authorization_url_is_mandatory(): diff --git a/tests/oauth2/authorization_code/test_oauth2_authorization_code_okta.py b/tests/oauth2/authorization_code/test_oauth2_authorization_code_okta.py index 073b289..2b24009 100644 --- a/tests/oauth2/authorization_code/test_oauth2_authorization_code_okta.py +++ b/tests/oauth2/authorization_code/test_oauth2_authorization_code_okta.py @@ -51,9 +51,7 @@ def test_oauth2_authorization_code_flow_uses_provided_session( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_uses_redirect_uri_domain( @@ -97,8 +95,75 @@ def test_oauth2_authorization_code_flow_uses_redirect_uri_domain( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." + tab.assert_success() + + +def test_oauth2_authorization_code_flow_uses_custom_success( + token_cache, responses: RequestsMock, browser_mock: BrowserMock +): + auth = requests_auth.OktaAuthorizationCode( + "testserver.okta-emea.com", + "54239d18-c68c-4c47-8bdd-ce71ea1d50cd", + ) + requests_auth.OAuth2.display.success_html = ( + "
SUCCESS: {display_time}
" + ) + tab = browser_mock.add_response( + opened_url="https://testserver.okta-emea.com/oauth2/default/v1/authorize?client_id=54239d18-c68c-4c47-8bdd-ce71ea1d50cd&scope=openid&response_type=code&state=5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#code=SplxlOBeZQQYbYS6WxSbIA&state=5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b", + displayed_html="
SUCCESS: {display_time}
", + ) + responses.post( + "https://testserver.okta-emea.com/oauth2/default/v1/token", + json={ + "access_token": "2YotnFZFEjr1zCsicMWpAA", + "token_type": "example", + "expires_in": 3600, + "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter": "example_value", + }, + match=[ + urlencoded_params_matcher( + { + "grant_type": "authorization_code", + "redirect_uri": "http://localhost:5000/", + "client_id": "54239d18-c68c-4c47-8bdd-ce71ea1d50cd", + "scope": "openid", + "response_type": "code", + "code": "SplxlOBeZQQYbYS6WxSbIA", + } + ), + ], + ) + responses.get( + "http://authorized_only", + match=[header_matcher({"Authorization": "Bearer 2YotnFZFEjr1zCsicMWpAA"})], + ) + + requests.get("http://authorized_only", auth=auth) + + tab.assert_success() + + +def test_oauth2_authorization_code_flow_uses_custom_failure( + token_cache, browser_mock: BrowserMock +): + auth = requests_auth.OktaAuthorizationCode( + "testserver.okta-emea.com", + "54239d18-c68c-4c47-8bdd-ce71ea1d50cd", + ) + requests_auth.OAuth2.display.failure_html = "FAILURE: {display_time}\n{information}" + tab = browser_mock.add_response( + opened_url="https://testserver.okta-emea.com/oauth2/default/v1/authorize?client_id=54239d18-c68c-4c47-8bdd-ce71ea1d50cd&scope=openid&response_type=code&state=5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#error=invalid_request", + displayed_html="FAILURE: {display_time}\n{information}", + ) + + with pytest.raises(requests_auth.InvalidGrantRequest): + requests.get("http://authorized_only", auth=auth) + + tab.assert_failure( + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -141,9 +206,7 @@ def test_okta_authorization_code_flow_get_code_is_sent_in_authorization_header_b requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_okta_authorization_code_flow_token_is_expired_after_30_seconds_by_default( @@ -192,9 +255,7 @@ def test_okta_authorization_code_flow_token_is_expired_after_30_seconds_by_defau requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_okta_authorization_code_flow_token_custom_expiry( @@ -245,9 +306,7 @@ def test_empty_token_is_invalid( str(exception_info.value) == "access_token not provided within {'access_token': '', 'token_type': 'example', 'expires_in': 3600, 'refresh_token': 'tGzv3JOkF0XG5Qx2TlKWIA', 'example_parameter': 'example_value'}." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_no_json( @@ -268,9 +327,7 @@ def test_with_invalid_grant_request_no_json( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "failure" - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error( @@ -297,9 +354,7 @@ def test_with_invalid_grant_request_invalid_request_error( "includes multiple credentials, utilizes more than one mechanism for " "authenticating the client, or is otherwise malformed." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description( @@ -320,9 +375,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc of the error" - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri( @@ -350,9 +403,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on http://test_url" ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri_and_other_fields( @@ -381,9 +432,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == "invalid_request: desc of the error\nMore information can be found on http://test_url\nAdditional information: {'other': 'other info'}" ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_without_error( @@ -404,9 +453,7 @@ def test_with_invalid_grant_request_without_error( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "{'other': 'other info'}" - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_client_error( @@ -437,9 +484,7 @@ def test_with_invalid_grant_request_invalid_client_error( 'code and include the "WWW-Authenticate" response header field matching the ' "authentication scheme used by the client." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_grant_error( @@ -466,9 +511,7 @@ def test_with_invalid_grant_request_invalid_grant_error( "does not match the redirection URI used in the authorization request, or was " "issued to another client." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unauthorized_client_error( @@ -493,9 +536,7 @@ def test_with_invalid_grant_request_unauthorized_client_error( == "unauthorized_client: The authenticated client is not authorized to use this " "authorization grant type." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unsupported_grant_type_error( @@ -520,9 +561,7 @@ def test_with_invalid_grant_request_unsupported_grant_type_error( == "unsupported_grant_type: The authorization grant type is not supported by the " "authorization server." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_scope_error( @@ -547,9 +586,7 @@ def test_with_invalid_grant_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, malformed, or " "exceeds the scope granted by the resource owner." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_token_request_invalid_request_error( @@ -569,7 +606,7 @@ def test_with_invalid_token_request_invalid_request_error( == "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -586,9 +623,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc" - tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc" - ) + tab.assert_failure("invalid_request: desc") def test_with_invalid_token_request_invalid_request_error_and_error_description_and_uri( @@ -608,7 +643,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url" + "invalid_request: desc
More information can be found on http://test_url" ) @@ -629,7 +664,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" + "invalid_request: desc
More information can be found on http://test_url
Additional information: {'other': ['test']}" ) @@ -650,7 +685,7 @@ def test_with_invalid_token_request_unauthorized_client_error( == "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." + "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) @@ -671,7 +706,7 @@ def test_with_invalid_token_request_access_denied_error( == "access_denied: The resource owner or authorization server denied the request." ) tab.assert_failure( - "Unable to properly perform authentication: access_denied: The resource owner or authorization server denied the request." + "access_denied: The resource owner or authorization server denied the request." ) @@ -692,7 +727,7 @@ def test_with_invalid_token_request_unsupported_response_type_error( == "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." + "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) @@ -713,7 +748,7 @@ def test_with_invalid_token_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, or malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_scope: The requested scope is invalid, unknown, or malformed." + "invalid_scope: The requested scope is invalid, unknown, or malformed." ) @@ -734,7 +769,7 @@ def test_with_invalid_token_request_server_error_error( == "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" + "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -755,7 +790,7 @@ def test_with_invalid_token_request_temporarily_unavailable_error( == "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" + "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) diff --git a/tests/oauth2/authorization_code/test_oauth2_authorization_code_wakatime.py b/tests/oauth2/authorization_code/test_oauth2_authorization_code_wakatime.py index c134764..4f78cbe 100644 --- a/tests/oauth2/authorization_code/test_oauth2_authorization_code_wakatime.py +++ b/tests/oauth2/authorization_code/test_oauth2_authorization_code_wakatime.py @@ -49,9 +49,7 @@ def test_oauth2_authorization_code_flow_uses_provided_client( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_uses_redirect_uri_domain( @@ -92,8 +90,73 @@ def test_oauth2_authorization_code_flow_uses_redirect_uri_domain( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." + tab.assert_success() + + +def test_oauth2_authorization_code_flow_uses_custom_success( + token_cache, responses: RequestsMock, browser_mock: BrowserMock +): + auth = requests_auth.WakaTimeAuthorizationCode( + "jPJQV0op6Pu3b66MWDi8b1wD", + "waka_sec_0c4MBGeR9LN74LzV5uelF9SgeQ32CqfeWpIuieneBbsL57dAAlqqJWDiVDJOlsSx61pVwHMKlsb3uMvU", + scope="email", + ) + requests_auth.OAuth2.display.success_html = ( + "
SUCCESS: {display_time}
" + ) + tab = browser_mock.add_response( + opened_url="https://wakatime.com/oauth/authorize?client_id=jPJQV0op6Pu3b66MWDi8b1wD&client_secret=waka_sec_0c4MBGeR9LN74LzV5uelF9SgeQ32CqfeWpIuieneBbsL57dAAlqqJWDiVDJOlsSx61pVwHMKlsb3uMvU&scope=email&response_type=code&state=5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#code=SplxlOBeZQQYbYS6WxSbIA&state=5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a", + displayed_html="
SUCCESS: {display_time}
", + ) + responses.post( + "https://wakatime.com/oauth/token", + body="access_token=waka_tok_12345&token_type=bearer&expires_in=3600&refresh_token=waka_ref_12345&scope=email&example_parameter=example_value", + content_type="text/html; charset=utf-8", + match=[ + urlencoded_params_matcher( + { + "grant_type": "authorization_code", + "redirect_uri": "http://localhost:5000/", + "client_id": "jPJQV0op6Pu3b66MWDi8b1wD", + "client_secret": "waka_sec_0c4MBGeR9LN74LzV5uelF9SgeQ32CqfeWpIuieneBbsL57dAAlqqJWDiVDJOlsSx61pVwHMKlsb3uMvU", + "scope": "email", + "response_type": "code", + "code": "SplxlOBeZQQYbYS6WxSbIA", + } + ) + ], + ) + responses.get( + "https://authorized_only", + match=[header_matcher({"Authorization": "Bearer waka_tok_12345"})], + ) + + requests.get("https://authorized_only", auth=auth) + + tab.assert_success() + + +def test_oauth2_authorization_code_flow_uses_custom_failure( + token_cache, browser_mock: BrowserMock +): + auth = requests_auth.WakaTimeAuthorizationCode( + "jPJQV0op6Pu3b66MWDi8b1wD", + "waka_sec_0c4MBGeR9LN74LzV5uelF9SgeQ32CqfeWpIuieneBbsL57dAAlqqJWDiVDJOlsSx61pVwHMKlsb3uMvU", + scope="email", + ) + requests_auth.OAuth2.display.failure_html = "FAILURE: {display_time}\n{information}" + tab = browser_mock.add_response( + opened_url="https://wakatime.com/oauth/authorize?client_id=jPJQV0op6Pu3b66MWDi8b1wD&client_secret=waka_sec_0c4MBGeR9LN74LzV5uelF9SgeQ32CqfeWpIuieneBbsL57dAAlqqJWDiVDJOlsSx61pVwHMKlsb3uMvU&scope=email&response_type=code&state=5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#error=invalid_request", + displayed_html="FAILURE: {display_time}\n{information}", + ) + + with pytest.raises(requests_auth.InvalidGrantRequest): + requests.get("http://authorized_only", auth=auth) + + tab.assert_failure( + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -134,9 +197,7 @@ def test_multiple_scopes_are_comma_separated( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 34f21f9ea8be7b1dfd3dd1673a9aea7c3a1737228b4f08bc11ebacb88449afaa658811f8022e9962927a0ec42805c0e3cc5e6b0d9185308216b298a686001a1f. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_get_code_is_sent_in_authorization_header_by_default( @@ -176,9 +237,7 @@ def test_oauth2_authorization_code_flow_get_code_is_sent_in_authorization_header requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_json_response_is_handled_even_if_unused( @@ -224,9 +283,7 @@ def test_json_response_is_handled_even_if_unused( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_get_code_is_expired_after_30_seconds_by_default( @@ -273,9 +330,7 @@ def test_oauth2_authorization_code_flow_get_code_is_expired_after_30_seconds_by_ requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_get_code_custom_expiry( @@ -338,9 +393,7 @@ def test_oauth2_authorization_code_flow_refresh_token( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() # response for refresh token grant responses.post( @@ -405,9 +458,7 @@ def test_oauth2_authorization_code_flow_refresh_token_invalid( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() # response for refresh token grant responses.post( @@ -442,9 +493,7 @@ def test_oauth2_authorization_code_flow_refresh_token_invalid( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_oauth2_authorization_code_flow_refresh_token_access_token_not_expired( @@ -484,9 +533,7 @@ def test_oauth2_authorization_code_flow_refresh_token_access_token_not_expired( requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() # expect Bearer token to remain the same requests.get("https://authorized_only", auth=auth) @@ -530,9 +577,7 @@ def test_empty_token_is_invalid( str(exception_info.value) == "access_token not provided within {'access_token': '', 'token_type': 'bearer', 'expires_in': '3600', 'refresh_token': 'waka_ref_12345', 'scope': 'email', 'example_parameter': 'example_value'}." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_no_json( @@ -557,9 +602,7 @@ def test_with_invalid_grant_request_no_json( with pytest.raises(requests_auth.InvalidGrantRequest, match="failure"): requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error( @@ -590,9 +633,7 @@ def test_with_invalid_grant_request_invalid_request_error( "includes multiple credentials, utilizes more than one mechanism for " "authenticating the client, or is otherwise malformed." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description( @@ -617,9 +658,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description( requests.get("https://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc of the error" - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri( @@ -651,9 +690,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on https://test_url" ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri_and_other_fields( @@ -686,9 +723,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == "invalid_request: desc of the error\nMore information can be found on https://test_url\nAdditional information: {'other': 'other info'}" ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_without_error( @@ -714,9 +749,7 @@ def test_with_invalid_grant_request_without_error( ): requests.get("https://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_client_error( @@ -751,9 +784,7 @@ def test_with_invalid_grant_request_invalid_client_error( 'code and include the "WWW-Authenticate" response header field matching the ' "authentication scheme used by the client." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_grant_error( @@ -784,9 +815,7 @@ def test_with_invalid_grant_request_invalid_grant_error( "does not match the redirection URI used in the authorization request, or was " "issued to another client." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unauthorized_client_error( @@ -815,9 +844,7 @@ def test_with_invalid_grant_request_unauthorized_client_error( == "unauthorized_client: The authenticated client is not authorized to use this " "authorization grant type." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unsupported_grant_type_error( @@ -846,9 +873,7 @@ def test_with_invalid_grant_request_unsupported_grant_type_error( == "unsupported_grant_type: The authorization grant type is not supported by the " "authorization server." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_scope_error( @@ -877,9 +902,7 @@ def test_with_invalid_grant_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, malformed, or " "exceeds the scope granted by the resource owner." ) - tab.assert_success( - "You are now authenticated on 5d0adb208bdbecaf5cfb6de0bf4ba0aea52986f3fc5ea7bc30c4b2db449c17e5c9d15f9a3926476cdaf1c72e9f73c7cfdc624dde0187c38d8c6b04532770df2a. You may close this tab." - ) + tab.assert_success() def test_with_invalid_token_request_invalid_request_error( @@ -903,7 +926,7 @@ def test_with_invalid_token_request_invalid_request_error( == "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -925,9 +948,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description( ): requests.get("https://authorized_only", auth=auth) - tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc" - ) + tab.assert_failure("invalid_request: desc") def test_with_invalid_token_request_invalid_request_error_and_error_description_and_uri( @@ -951,7 +972,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on https://test_url" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on https://test_url" + "invalid_request: desc
More information can be found on https://test_url" ) @@ -976,7 +997,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on https://test_url\nAdditional information: {'other': ['test']}" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on https://test_url\nAdditional information: {'other': ['test']}" + "invalid_request: desc
More information can be found on https://test_url
Additional information: {'other': ['test']}" ) @@ -1001,7 +1022,7 @@ def test_with_invalid_token_request_unauthorized_client_error( == "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." + "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) @@ -1026,7 +1047,7 @@ def test_with_invalid_token_request_access_denied_error( == "access_denied: The resource owner or authorization server denied the request." ) tab.assert_failure( - "Unable to properly perform authentication: access_denied: The resource owner or authorization server denied the request." + "access_denied: The resource owner or authorization server denied the request." ) @@ -1051,7 +1072,7 @@ def test_with_invalid_token_request_unsupported_response_type_error( == "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." + "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) @@ -1076,7 +1097,7 @@ def test_with_invalid_token_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, or malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_scope: The requested scope is invalid, unknown, or malformed." + "invalid_scope: The requested scope is invalid, unknown, or malformed." ) @@ -1101,7 +1122,7 @@ def test_with_invalid_token_request_server_error_error( == "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" + "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -1126,7 +1147,7 @@ def test_with_invalid_token_request_temporarily_unavailable_error( == "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" + "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) diff --git a/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce.py b/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce.py index cf5a23b..7bfb9f2 100644 --- a/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce.py +++ b/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce.py @@ -52,9 +52,7 @@ def test_oauth2_pkce_flow_uses_provided_session( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_flow_uses_redirect_uri_domain( @@ -100,8 +98,80 @@ def test_oauth2_pkce_flow_uses_redirect_uri_domain( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." + tab.assert_success() + + +def test_oauth2_pkce_flow_uses_custom_success( + token_cache, responses: RequestsMock, monkeypatch, browser_mock: BrowserMock +): + monkeypatch.setattr( + requests_auth._oauth2.authorization_code_pkce.os, "urandom", lambda x: b"1" * 63 + ) + auth = requests_auth.OAuth2AuthorizationCodePKCE( + "http://provide_code", + "http://provide_access_token", + ) + requests_auth.OAuth2.display.success_html = ( + "
SUCCESS: {display_time}
" + ) + tab = browser_mock.add_response( + opened_url="http://provide_code?response_type=code&state=163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F&code_challenge=5C_ph_KZ3DstYUc965SiqmKAA-ShvKF4Ut7daKd3fjc&code_challenge_method=S256", + reply_url="http://localhost:5000#code=SplxlOBeZQQYbYS6WxSbIA&state=163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de", + displayed_html="
SUCCESS: {display_time}
", + ) + responses.post( + "http://provide_access_token", + json={ + "access_token": "2YotnFZFEjr1zCsicMWpAA", + "token_type": "example", + "expires_in": 3600, + "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter": "example_value", + }, + match=[ + urlencoded_params_matcher( + { + "code_verifier": "MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEx", + "grant_type": "authorization_code", + "redirect_uri": "http://localhost:5000/", + "response_type": "code", + "code": "SplxlOBeZQQYbYS6WxSbIA", + } + ), + ], + ) + responses.get( + "http://authorized_only", + match=[header_matcher({"Authorization": "Bearer 2YotnFZFEjr1zCsicMWpAA"})], + ) + + requests.get("http://authorized_only", auth=auth) + + tab.assert_success() + + +def test_oauth2_pkce_flow_uses_custom_failure( + token_cache, monkeypatch, browser_mock: BrowserMock +): + monkeypatch.setattr( + requests_auth._oauth2.authorization_code_pkce.os, "urandom", lambda x: b"1" * 63 + ) + auth = requests_auth.OAuth2AuthorizationCodePKCE( + "http://provide_code", + "http://provide_access_token", + ) + requests_auth.OAuth2.display.failure_html = "FAILURE: {display_time}\n{information}" + tab = browser_mock.add_response( + opened_url="http://provide_code?response_type=code&state=163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F&code_challenge=5C_ph_KZ3DstYUc965SiqmKAA-ShvKF4Ut7daKd3fjc&code_challenge_method=S256", + reply_url="http://localhost:5000#error=invalid_request", + displayed_html="FAILURE: {display_time}\n{information}", + ) + + with pytest.raises(requests_auth.InvalidGrantRequest): + requests.get("http://authorized_only", auth=auth) + + tab.assert_failure( + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -146,9 +216,7 @@ def test_oauth2_pkce_flow_get_code_is_sent_in_authorization_header_by_default( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_flow_token_is_expired_after_30_seconds_by_default( @@ -199,9 +267,7 @@ def test_oauth2_pkce_flow_token_is_expired_after_30_seconds_by_default( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_oauth2_client_credentials_flow_token_custom_expiry( @@ -270,9 +336,7 @@ def test_expires_in_sent_as_str( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_refresh_token( @@ -316,9 +380,7 @@ def test_refresh_token( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() # response for refresh token grant responses.post( "http://provide_access_token", @@ -388,9 +450,7 @@ def test_refresh_token_invalid( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() # response for refresh token grant responses.post( "http://provide_access_token", @@ -421,9 +481,7 @@ def test_refresh_token_invalid( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_refresh_token_access_token_not_expired( @@ -467,9 +525,7 @@ def test_refresh_token_access_token_not_expired( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() # expect Bearer token to remain the same response = requests.get("http://authorized_only", auth=auth) @@ -519,9 +575,7 @@ def test_nonce_is_sent_if_provided_in_authorization_url( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_no_json( @@ -541,9 +595,7 @@ def test_with_invalid_grant_request_no_json( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "failure" - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error( @@ -573,9 +625,7 @@ def test_with_invalid_grant_request_invalid_request_error( "includes multiple credentials, utilizes more than one mechanism for " "authenticating the client, or is otherwise malformed." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description( @@ -599,9 +649,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc of the error" - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri( @@ -632,9 +680,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on http://test_url" ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri_and_other_fields( @@ -666,9 +712,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on http://test_url\nAdditional information: {{'other': 'other info'}}" ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_without_error( @@ -692,9 +736,7 @@ def test_with_invalid_grant_request_without_error( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "{'other': 'other info'}" - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_client_error( @@ -728,9 +770,7 @@ def test_with_invalid_grant_request_invalid_client_error( 'code and include the "WWW-Authenticate" response header field matching the ' "authentication scheme used by the client." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_grant_error( @@ -760,9 +800,7 @@ def test_with_invalid_grant_request_invalid_grant_error( "does not match the redirection URI used in the authorization request, or was " "issued to another client." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unauthorized_client_error( @@ -790,9 +828,7 @@ def test_with_invalid_grant_request_unauthorized_client_error( == "unauthorized_client: The authenticated client is not authorized to use this " "authorization grant type." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unsupported_grant_type_error( @@ -820,9 +856,7 @@ def test_with_invalid_grant_request_unsupported_grant_type_error( == "unsupported_grant_type: The authorization grant type is not supported by the " "authorization server." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_scope_error( @@ -850,9 +884,7 @@ def test_with_invalid_grant_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, malformed, or " "exceeds the scope granted by the resource owner." ) - tab.assert_success( - "You are now authenticated on 163f0455b3e9cad3ca04254e5a0169553100d3aa0756c7964d897da316a695ffed5b4f46ef305094fd0a88cfe4b55ff257652015e4aa8f87b97513dba440f8de. You may close this tab." - ) + tab.assert_success() def test_with_invalid_token_request_invalid_request_error( @@ -875,7 +907,7 @@ def test_with_invalid_token_request_invalid_request_error( == "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -895,9 +927,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc" - tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc" - ) + tab.assert_failure("invalid_request: desc") def test_with_invalid_token_request_invalid_request_error_and_error_description_and_uri( @@ -920,7 +950,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url" + "invalid_request: desc
More information can be found on http://test_url" ) @@ -944,7 +974,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" + "invalid_request: desc
More information can be found on http://test_url
Additional information: {'other': ['test']}" ) @@ -968,7 +998,7 @@ def test_with_invalid_token_request_unauthorized_client_error( == "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." + "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) @@ -992,7 +1022,7 @@ def test_with_invalid_token_request_access_denied_error( == "access_denied: The resource owner or authorization server denied the request." ) tab.assert_failure( - "Unable to properly perform authentication: access_denied: The resource owner or authorization server denied the request." + "access_denied: The resource owner or authorization server denied the request." ) @@ -1016,7 +1046,7 @@ def test_with_invalid_token_request_unsupported_response_type_error( == "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." + "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) @@ -1040,7 +1070,7 @@ def test_with_invalid_token_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, or malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_scope: The requested scope is invalid, unknown, or malformed." + "invalid_scope: The requested scope is invalid, unknown, or malformed." ) @@ -1064,7 +1094,7 @@ def test_with_invalid_token_request_server_error_error( == "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" + "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -1088,7 +1118,7 @@ def test_with_invalid_token_request_temporarily_unavailable_error( == "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" + "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -1135,9 +1165,7 @@ def test_response_type_can_be_provided_in_url( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on b32e05720bd3722e0ac87bf72897a78b669a0810adf8da46b675793dcfe0f41a40f7d7fdda952bd73ea533a2462907d805adf8c1a162d51b99b2ddec0d411feb. You may close this tab." - ) + tab.assert_success() def test_authorization_url_is_mandatory(): diff --git a/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce_okta.py b/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce_okta.py index 1eb8eb3..e3e8634 100644 --- a/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce_okta.py +++ b/tests/oauth2/authorization_code_pkce/test_oauth2_authorization_code_pkce_okta.py @@ -56,9 +56,7 @@ def test_oauth2_pkce_flow_uses_provided_session( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_oauth2_pkce_flow_uses_redirect_uri_domain( @@ -106,8 +104,82 @@ def test_oauth2_pkce_flow_uses_redirect_uri_domain( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." + tab.assert_success() + + +def test_oauth2_pkce_flow_uses_custom_success( + token_cache, responses: RequestsMock, monkeypatch, browser_mock: BrowserMock +): + monkeypatch.setattr( + requests_auth._oauth2.authorization_code_pkce.os, "urandom", lambda x: b"1" * 63 + ) + auth = requests_auth.OktaAuthorizationCodePKCE( + "testserver.okta-emea.com", + "54239d18-c68c-4c47-8bdd-ce71ea1d50cd", + ) + requests_auth.OAuth2.display.success_html = ( + "
SUCCESS: {display_time}
" + ) + tab = browser_mock.add_response( + opened_url="https://testserver.okta-emea.com/oauth2/default/v1/authorize?client_id=54239d18-c68c-4c47-8bdd-ce71ea1d50cd&scope=openid&response_type=code&state=5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F&code_challenge=5C_ph_KZ3DstYUc965SiqmKAA-ShvKF4Ut7daKd3fjc&code_challenge_method=S256", + reply_url="http://localhost:5000#code=SplxlOBeZQQYbYS6WxSbIA&state=5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b", + displayed_html="
SUCCESS: {display_time}
", + ) + responses.post( + "https://testserver.okta-emea.com/oauth2/default/v1/token", + json={ + "access_token": "2YotnFZFEjr1zCsicMWpAA", + "token_type": "example", + "expires_in": 3600, + "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter": "example_value", + }, + match=[ + urlencoded_params_matcher( + { + "code_verifier": "MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEx", + "grant_type": "authorization_code", + "redirect_uri": "http://localhost:5000/", + "client_id": "54239d18-c68c-4c47-8bdd-ce71ea1d50cd", + "scope": "openid", + "response_type": "code", + "code": "SplxlOBeZQQYbYS6WxSbIA", + } + ), + ], + ) + responses.get( + "http://authorized_only", + match=[header_matcher({"Authorization": "Bearer 2YotnFZFEjr1zCsicMWpAA"})], + ) + + requests.get("http://authorized_only", auth=auth) + + tab.assert_success() + + +def test_oauth2_pkce_flow_uses_custom_failure( + token_cache, monkeypatch, browser_mock: BrowserMock +): + monkeypatch.setattr( + requests_auth._oauth2.authorization_code_pkce.os, "urandom", lambda x: b"1" * 63 + ) + auth = requests_auth.OktaAuthorizationCodePKCE( + "testserver.okta-emea.com", + "54239d18-c68c-4c47-8bdd-ce71ea1d50cd", + ) + requests_auth.OAuth2.display.failure_html = "FAILURE: {display_time}\n{information}" + tab = browser_mock.add_response( + opened_url="https://testserver.okta-emea.com/oauth2/default/v1/authorize?client_id=54239d18-c68c-4c47-8bdd-ce71ea1d50cd&scope=openid&response_type=code&state=5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F&code_challenge=5C_ph_KZ3DstYUc965SiqmKAA-ShvKF4Ut7daKd3fjc&code_challenge_method=S256", + reply_url="http://localhost:5000#error=invalid_request", + displayed_html="FAILURE: {display_time}\n{information}", + ) + + with pytest.raises(requests_auth.InvalidGrantRequest): + requests.get("http://authorized_only", auth=auth) + + tab.assert_failure( + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -154,9 +226,7 @@ def test_oauth2_pkce_flow_get_code_is_sent_in_authorization_header_by_default( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_okta_pkce_flow_token_is_expired_after_30_seconds_by_default( @@ -209,9 +279,7 @@ def test_okta_pkce_flow_token_is_expired_after_30_seconds_by_default( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_okta_pkce_flow_token_custom_expiry( @@ -282,9 +350,7 @@ def test_expires_in_sent_as_str( requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_no_json( @@ -308,9 +374,7 @@ def test_with_invalid_grant_request_no_json( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "failure" - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error( @@ -340,9 +404,7 @@ def test_with_invalid_grant_request_invalid_request_error( "includes multiple credentials, utilizes more than one mechanism for " "authenticating the client, or is otherwise malformed." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description( @@ -366,9 +428,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc of the error" - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri( @@ -399,9 +459,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on http://test_url" ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_request_error_and_error_description_and_uri_and_other_fields( @@ -433,9 +491,7 @@ def test_with_invalid_grant_request_invalid_request_error_and_error_description_ str(exception_info.value) == f"invalid_request: desc of the error\nMore information can be found on http://test_url\nAdditional information: {{'other': 'other info'}}" ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_without_error( @@ -459,9 +515,7 @@ def test_with_invalid_grant_request_without_error( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "{'other': 'other info'}" - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_client_error( @@ -495,9 +549,7 @@ def test_with_invalid_grant_request_invalid_client_error( 'code and include the "WWW-Authenticate" response header field matching the ' "authentication scheme used by the client." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_grant_error( @@ -527,9 +579,7 @@ def test_with_invalid_grant_request_invalid_grant_error( "does not match the redirection URI used in the authorization request, or was " "issued to another client." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unauthorized_client_error( @@ -557,9 +607,7 @@ def test_with_invalid_grant_request_unauthorized_client_error( == "unauthorized_client: The authenticated client is not authorized to use this " "authorization grant type." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_unsupported_grant_type_error( @@ -587,9 +635,7 @@ def test_with_invalid_grant_request_unsupported_grant_type_error( == "unsupported_grant_type: The authorization grant type is not supported by the " "authorization server." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_grant_request_invalid_scope_error( @@ -617,9 +663,7 @@ def test_with_invalid_grant_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, malformed, or " "exceeds the scope granted by the resource owner." ) - tab.assert_success( - "You are now authenticated on 5264d11c8b268ccf911ce564ca42fd75cea68c4a3c1ec3ac1ab20243891ab7cd5250ad4c2d002017c6e8ac2ba34954293baa5e0e4fd00bb9ffd4a39c45f1960b. You may close this tab." - ) + tab.assert_success() def test_with_invalid_token_request_invalid_request_error( @@ -642,7 +686,7 @@ def test_with_invalid_token_request_invalid_request_error( == "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -662,9 +706,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description( with pytest.raises(requests_auth.InvalidGrantRequest) as exception_info: requests.get("http://authorized_only", auth=auth) assert str(exception_info.value) == "invalid_request: desc" - tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc" - ) + tab.assert_failure("invalid_request: desc") def test_with_invalid_token_request_invalid_request_error_and_error_description_and_uri( @@ -687,7 +729,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url" + "invalid_request: desc
More information can be found on http://test_url" ) @@ -711,7 +753,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" + "invalid_request: desc
More information can be found on http://test_url
Additional information: {'other': ['test']}" ) @@ -735,7 +777,7 @@ def test_with_invalid_token_request_unauthorized_client_error( == "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." + "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) @@ -759,7 +801,7 @@ def test_with_invalid_token_request_access_denied_error( == "access_denied: The resource owner or authorization server denied the request." ) tab.assert_failure( - "Unable to properly perform authentication: access_denied: The resource owner or authorization server denied the request." + "access_denied: The resource owner or authorization server denied the request." ) @@ -783,7 +825,7 @@ def test_with_invalid_token_request_unsupported_response_type_error( == "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." + "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) @@ -807,7 +849,7 @@ def test_with_invalid_token_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, or malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_scope: The requested scope is invalid, unknown, or malformed." + "invalid_scope: The requested scope is invalid, unknown, or malformed." ) @@ -831,7 +873,7 @@ def test_with_invalid_token_request_server_error_error( == "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" + "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -855,7 +897,7 @@ def test_with_invalid_token_request_temporarily_unavailable_error( == "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" + "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) diff --git a/tests/oauth2/implicit/test_oauth2_implicit.py b/tests/oauth2/implicit/test_oauth2_implicit.py index a19e619..abc23b3 100644 --- a/tests/oauth2/implicit/test_oauth2_implicit.py +++ b/tests/oauth2/implicit/test_oauth2_implicit.py @@ -72,12 +72,8 @@ def test_oauth2_implicit_flow_token_is_not_reused_if_a_url_parameter_is_changing requests.get("http://authorized_only", auth=auth2) - tab1.assert_success( - "You are now authenticated on 5652a8138e3a99dab7b94532c73ed5b10f19405316035d1efdc8bf7e0713690485254c2eaff912040eac44031889ef0a5ed5730c8a111541120d64a898c31afe. You may close this tab." - ) - tab2.assert_success( - "You are now authenticated on 5c3940ccf78ac6e7d6d8d06782d9fd95a533aa5425b616eaa38dc3ec9508fbd55152c58a0d8dd8a087e76b77902559285819a41cb78ce8713e5a3b974bf07ce9. You may close this tab." - ) + tab1.assert_success() + tab2.assert_success() def test_oauth2_implicit_flow_token_is_reused_if_only_nonce_differs( @@ -113,9 +109,7 @@ def test_oauth2_implicit_flow_token_is_reused_if_only_nonce_differs( ) requests.get("http://authorized_only", auth=auth2) - tab.assert_success( - "You are now authenticated on 67b95d2c7555751d1d72c97c7cd9ad6630c8395e0eaa51ee86ac7e451211ded9cd98a7190848789fe93632d8960425710e93f1f5549c6c6bc328bf3865a85ff2. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_token_can_be_requested_on_a_custom_server_port( @@ -141,9 +135,7 @@ def test_oauth2_implicit_flow_token_can_be_requested_on_a_custom_server_port( ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_uses_redirect_uri_domain( @@ -167,8 +159,51 @@ def test_oauth2_implicit_flow_uses_redirect_uri_domain( ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." + tab.assert_success() + + +def test_oauth2_implicit_flow_uses_custom_success( + token_cache, responses: RequestsMock, browser_mock: BrowserMock +): + auth = requests_auth.OAuth2Implicit("http://provide_token") + requests_auth.OAuth2.display.success_html = ( + "
SUCCESS: {display_time}
" + ) + expiry_in_1_hour = datetime.datetime.now( + datetime.timezone.utc + ) + datetime.timedelta(hours=1) + token = create_token(expiry_in_1_hour) + tab = browser_mock.add_response( + opened_url="http://provide_token?response_type=token&state=42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000", + displayed_html="
SUCCESS: {display_time}
", + data=f"access_token={token}&state=42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521", + ) + responses.get( + "http://authorized_only", + match=[header_matcher({"Authorization": f"Bearer {token}"})], + ) + + requests.get("http://authorized_only", auth=auth) + tab.assert_success() + + +def test_oauth2_implicit_flow_uses_custom_failure( + token_cache, browser_mock: BrowserMock +): + auth = requests_auth.OAuth2Implicit("http://provide_token") + requests_auth.OAuth2.display.failure_html = "FAILURE: {display_time}\n{information}" + tab = browser_mock.add_response( + opened_url="http://provide_token?response_type=token&state=42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F", + reply_url="http://localhost:5000#error=invalid_request", + displayed_html="FAILURE: {display_time}\n{information}", + ) + + with pytest.raises(requests_auth.InvalidGrantRequest): + requests.get("http://authorized_only", auth=auth) + + tab.assert_failure( + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -191,9 +226,7 @@ def test_oauth2_implicit_flow_post_token_is_sent_in_authorization_header_by_defa ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_token_is_expired_after_30_seconds_by_default( @@ -225,9 +258,7 @@ def test_oauth2_implicit_flow_token_is_expired_after_30_seconds_by_default( ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_token_custom_expiry( @@ -325,7 +356,7 @@ def test_state_change(token_cache, responses: RequestsMock, browser_mock: Browse ) requests.get("http://authorized_only", auth=auth) - tab.assert_success("You are now authenticated on 123456. You may close this tab.") + tab.assert_success() def test_empty_token_is_invalid(token_cache, browser_mock: BrowserMock): @@ -340,9 +371,7 @@ def test_empty_token_is_invalid(token_cache, browser_mock: BrowserMock): auth=requests_auth.OAuth2Implicit("http://provide_token"), ) assert str(exception_info.value) == " is invalid." - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_token_without_expiry_is_invalid(token_cache, browser_mock: BrowserMock): @@ -357,9 +386,7 @@ def test_token_without_expiry_is_invalid(token_cache, browser_mock: BrowserMock) auth=requests_auth.OAuth2Implicit("http://provide_token"), ) assert str(exception_info.value) == "Expiry (exp) is not provided in None." - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_get_token_is_sent_in_authorization_header_by_default( @@ -380,9 +407,7 @@ def test_oauth2_implicit_flow_get_token_is_sent_in_authorization_header_by_defau ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_token_is_sent_in_requested_field( @@ -406,9 +431,7 @@ def test_oauth2_implicit_flow_token_is_sent_in_requested_field( ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_can_send_a_custom_response_type_and_expects_token_to_be_received_with_this_name( @@ -434,9 +457,7 @@ def test_oauth2_implicit_flow_can_send_a_custom_response_type_and_expects_token_ ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 67b95d2c7555751d1d72c97c7cd9ad6630c8395e0eaa51ee86ac7e451211ded9cd98a7190848789fe93632d8960425710e93f1f5549c6c6bc328bf3865a85ff2. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_expects_token_in_id_token_if_response_type_is_id_token( @@ -460,9 +481,7 @@ def test_oauth2_implicit_flow_expects_token_in_id_token_if_response_type_is_id_t ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 87c4108ec0eb03599335333a40434a36674269690b6957fef684bfb6c5a849ce660ef7031aa874c44d67cd3eada8febdfce41efb1ed3bc53a0a7e716cbba025a. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_expects_token_in_id_token_if_response_type_in_url_is_id_token( @@ -484,9 +503,7 @@ def test_oauth2_implicit_flow_expects_token_in_id_token_if_response_type_in_url_ ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 87c4108ec0eb03599335333a40434a36674269690b6957fef684bfb6c5a849ce660ef7031aa874c44d67cd3eada8febdfce41efb1ed3bc53a0a7e716cbba025a. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_expects_token_to_be_stored_in_access_token_by_default( @@ -508,9 +525,7 @@ def test_oauth2_implicit_flow_expects_token_to_be_stored_in_access_token_by_defa ) requests.get("http://authorized_only", auth=auth) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_token_is_reused_if_not_expired( @@ -540,9 +555,7 @@ def test_oauth2_implicit_flow_token_is_reused_if_not_expired( ) requests.get("http://authorized_only", auth=oauth2) - tab.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab.assert_success() def test_oauth2_implicit_flow_post_failure_if_token_is_not_provided( @@ -559,9 +572,7 @@ def test_oauth2_implicit_flow_post_failure_if_token_is_not_provided( auth=requests_auth.OAuth2Implicit("http://provide_token"), ) assert str(exception_info.value) == "access_token not provided within {}." - tab.assert_failure( - "Unable to properly perform authentication: access_token not provided within {}." - ) + tab.assert_failure("access_token not provided within {}.") def test_oauth2_implicit_flow_get_failure_if_token_is_not_provided( @@ -577,9 +588,7 @@ def test_oauth2_implicit_flow_get_failure_if_token_is_not_provided( auth=requests_auth.OAuth2Implicit("http://provide_token"), ) assert str(exception_info.value) == "access_token not provided within {}." - tab.assert_failure( - "Unable to properly perform authentication: access_token not provided within {}." - ) + tab.assert_failure("access_token not provided within {}.") def test_oauth2_implicit_flow_post_failure_if_state_is_not_provided( @@ -603,9 +612,7 @@ def test_oauth2_implicit_flow_post_failure_if_state_is_not_provided( str(exception_info.value) == f"state not provided within {{'access_token': ['{token}']}}." ) - tab.assert_failure( - f"Unable to properly perform authentication: state not provided within {{'access_token': ['{token}']}}." - ) + tab.assert_failure(f"state not provided within {{'access_token': ['{token}']}}.") def test_oauth2_implicit_flow_get_failure_if_state_is_not_provided( @@ -629,7 +636,7 @@ def test_oauth2_implicit_flow_get_failure_if_state_is_not_provided( == f"state not provided within {{'access_token': ['{token}'], 'requests_auth_redirect': ['1']}}." ) tab.assert_failure( - f"Unable to properly perform authentication: state not provided within {{'access_token': ['{token}'], 'requests_auth_redirect': ['1']}}." + f"state not provided within {{'access_token': ['{token}'], 'requests_auth_redirect': ['1']}}." ) @@ -650,7 +657,7 @@ def test_with_invalid_token_request_invalid_request_error( == "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." + "invalid_request: The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." ) @@ -667,9 +674,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description( auth=requests_auth.OAuth2Implicit("http://provide_token"), ) assert str(exception_info.value) == "invalid_request: desc" - tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc" - ) + tab.assert_failure("invalid_request: desc") def test_with_invalid_token_request_invalid_request_error_and_error_description_and_uri( @@ -689,7 +694,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url" + "invalid_request: desc
More information can be found on http://test_url" ) @@ -710,7 +715,7 @@ def test_with_invalid_token_request_invalid_request_error_and_error_description_ == "invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" ) tab.assert_failure( - "Unable to properly perform authentication: invalid_request: desc\nMore information can be found on http://test_url\nAdditional information: {'other': ['test']}" + "invalid_request: desc
More information can be found on http://test_url
Additional information: {'other': ['test']}" ) @@ -731,7 +736,7 @@ def test_with_invalid_token_request_unauthorized_client_error( == "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." + "unauthorized_client: The client is not authorized to request an authorization code or an access token using this method." ) @@ -752,7 +757,7 @@ def test_with_invalid_token_request_access_denied_error( == "access_denied: The resource owner or authorization server denied the request." ) tab.assert_failure( - "Unable to properly perform authentication: access_denied: The resource owner or authorization server denied the request." + "access_denied: The resource owner or authorization server denied the request." ) @@ -773,7 +778,7 @@ def test_with_invalid_token_request_unsupported_response_type_error( == "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) tab.assert_failure( - "Unable to properly perform authentication: unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." + "unsupported_response_type: The authorization server does not support obtaining an authorization code or an access token using this method." ) @@ -794,7 +799,7 @@ def test_with_invalid_token_request_invalid_scope_error( == "invalid_scope: The requested scope is invalid, unknown, or malformed." ) tab.assert_failure( - "Unable to properly perform authentication: invalid_scope: The requested scope is invalid, unknown, or malformed." + "invalid_scope: The requested scope is invalid, unknown, or malformed." ) @@ -815,7 +820,7 @@ def test_with_invalid_token_request_server_error_error( == "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" + "server_error: The authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -836,7 +841,7 @@ def test_with_invalid_token_request_temporarily_unavailable_error( == "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) tab.assert_failure( - "Unable to properly perform authentication: temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" + "temporarily_unavailable: The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)" ) @@ -899,9 +904,5 @@ def test_oauth2_implicit_flow_token_is_requested_again_if_expired( ) requests.get("http://authorized_only", auth=auth) - tab1.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) - tab2.assert_success( - "You are now authenticated on 42a85b271b7a652ca3cc4c398cfd3f01b9ad36bf9c945ba823b023e8f8b95c4638576a0e3dcc96838b838bec33ec6c0ee2609d62ed82480b3b8114ca494c0521. You may close this tab." - ) + tab1.assert_success() + tab2.assert_success()