Skip to content

Commit

Permalink
Merge pull request Colin-b#82 from Colin-b/bugfix/fqdn
Browse files Browse the repository at this point in the history
Add support for localhost FQDN
  • Loading branch information
Colin-b authored Feb 18, 2024
2 parents f6a8313 + beada40 commit 0bd9b23
Show file tree
Hide file tree
Showing 21 changed files with 635 additions and 178 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.21.0] - 2024-02-19
### Added
- Publicly expose `httpx_auth.SupportMultiAuth`, allowing multiple authentication support for every `httpx` authentication class that exists.
- Publicly expose `httpx_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.
- Support for refresh tokens in the Resource Owner Password Credentials flow.
- Support for refresh tokens in the Authorization code (with and without PKCE) flow.
- 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.

### Changed
- Except for `httpx_auth.testing`, only direct access via `httpx_auth.` was considered publicly exposed. This is now explicit, as inner packages are now using private prefix (`_`).
Expand Down Expand Up @@ -242,7 +245,8 @@ Note that a few changes were made:
### Added
- Placeholder for port of requests_auth to httpx

[Unreleased]: https://github.com/Colin-b/httpx_auth/compare/v0.20.0...HEAD
[Unreleased]: https://github.com/Colin-b/httpx_auth/compare/v0.21.0...HEAD
[0.21.0]: https://github.com/Colin-b/httpx_auth/compare/v0.20.0...v0.21.0
[0.20.0]: https://github.com/Colin-b/httpx_auth/compare/v0.19.0...v0.20.0
[0.19.0]: https://github.com/Colin-b/httpx_auth/compare/v0.18.0...v0.19.0
[0.18.0]: https://github.com/Colin-b/httpx_auth/compare/v0.17.0...v0.18.0
Expand Down
62 changes: 36 additions & 26 deletions README.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion httpx_auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
QueryApiKey,
SupportMultiAuth,
)
from httpx_auth._oauth2.common import OAuth2, DisplaySettings
from httpx_auth._oauth2.browser import DisplaySettings
from httpx_auth._oauth2.common import OAuth2
from httpx_auth._oauth2.authorization_code import (
OAuth2AuthorizationCode,
OktaAuthorizationCode,
Expand Down
7 changes: 5 additions & 2 deletions httpx_auth/_oauth2/authorization_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

import httpx

from httpx_auth._oauth2 import authentication_responses_server
from httpx_auth._authentication import SupportMultiAuth
from httpx_auth._oauth2 import authentication_responses_server
from httpx_auth._oauth2.browser import BrowserAuth
from httpx_auth._oauth2.common import (
request_new_grant_with_post,
OAuth2,
_add_parameters,
_pop_parameter,
BrowserAuth,
_get_query_parameter,
)

Expand All @@ -31,6 +31,7 @@ def __init__(self, authorization_url: str, token_url: str, **kwargs):
"""
:param authorization_url: OAuth 2 authorization URL.
:param token_url: OAuth 2 token URL.
:param redirect_uri_domain: FQDN to use in the redirect_uri when localhost (default) is not allowed.
:param redirect_uri_endpoint: Custom endpoint that will be used as redirect_uri the following way:
http://localhost:<redirect_uri_port>/<redirect_uri_endpoint>. Default value is to redirect on / (root).
:param redirect_uri_port: The port on which the server listening for the OAuth 2 code will be started.
Expand Down Expand Up @@ -212,6 +213,7 @@ def __init__(self, instance: str, client_id: str, **kwargs):
default by default.
:param scope: Scope parameter sent in query. Can also be a list of scopes.
Request 'openid' by default.
:param redirect_uri_domain: FQDN to use in the redirect_uri when localhost (default) is not allowed.
:param redirect_uri_endpoint: Custom endpoint that will be used as redirect_uri the following way:
http://localhost:<redirect_uri_port>/<redirect_uri_endpoint>. Default value is to redirect on / (root).
:param redirect_uri_port: The port on which the server listening for the OAuth 2 token will be started.
Expand Down Expand Up @@ -267,6 +269,7 @@ def __init__(
reaches the actual server. Set it to 0 to deactivate this feature and use the same token until actual expiry.
:param nonce: Refer to http://openid.net/specs/openid-connect-core-1_0.html#IDToken for more details
(formatted as a Universal Unique Identifier - UUID). Use a newly generated UUID by default.
:param redirect_uri_domain: FQDN to use in the redirect_uri when localhost (default) is not allowed.
:param redirect_uri_endpoint: Custom endpoint that will be used as redirect_uri the following way:
http://localhost:<redirect_uri_port>/<redirect_uri_endpoint>. Default value is to redirect on / (root).
:param redirect_uri_port: The port on which the server listening for the OAuth 2 token will be started.
Expand Down
6 changes: 4 additions & 2 deletions httpx_auth/_oauth2/authorization_code_pkce.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

import httpx

from httpx_auth._oauth2 import authentication_responses_server
from httpx_auth._authentication import SupportMultiAuth
from httpx_auth._oauth2 import authentication_responses_server
from httpx_auth._oauth2.browser import BrowserAuth
from httpx_auth._oauth2.common import (
request_new_grant_with_post,
OAuth2,
_add_parameters,
_pop_parameter,
BrowserAuth,
)


Expand All @@ -32,6 +32,7 @@ def __init__(self, authorization_url: str, token_url: str, **kwargs):
"""
:param authorization_url: OAuth 2 authorization URL.
:param token_url: OAuth 2 token URL.
:param redirect_uri_domain: FQDN to use in the redirect_uri when localhost (default) is not allowed.
:param redirect_uri_endpoint: Custom endpoint that will be used as redirect_uri the following way:
http://localhost:<redirect_uri_port>/<redirect_uri_endpoint>. Default value is to redirect on / (root).
:param redirect_uri_port: The port on which the server listening for the OAuth 2 code will be started.
Expand Down Expand Up @@ -254,6 +255,7 @@ def __init__(self, instance: str, client_id: str, **kwargs):
default by default.
:param scope: Scope parameter sent in query. Can also be a list of scopes.
Request 'openid' by default.
:param redirect_uri_domain: FQDN to use in the redirect_uri when localhost (default) is not allowed.
:param redirect_uri_endpoint: Custom endpoint that will be used as redirect_uri the following way:
http://localhost:<redirect_uri_port>/<redirect_uri_endpoint>. Default value is to redirect on / (root).
:param redirect_uri_port: The port on which the server listening for the OAuth 2 token will be started.
Expand Down
140 changes: 140 additions & 0 deletions httpx_auth/_oauth2/browser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
class BrowserAuth:
def __init__(self, kwargs):
"""
:param redirect_uri_domain: FQDN to use in the redirect_uri when localhost (default) is not allowed.
:param redirect_uri_endpoint: Custom endpoint that will be used as redirect_uri the following way:
http://<redirect_uri_domain>:<redirect_uri_port>/<redirect_uri_endpoint>. Default value is to redirect on / (root).
:param redirect_uri_port: The port on which the server listening for the OAuth 2 code will be started.
Listen on port 5000 by default.
:param timeout: Maximum amount of seconds to wait for a code or a token to be received once requested.
Wait for 1 minute (60 seconds) by default.
"""
redirect_uri_domain = kwargs.pop("redirect_uri_domain", None) or "localhost"
redirect_uri_endpoint = kwargs.pop("redirect_uri_endpoint", None) or ""
self.redirect_uri_port = int(kwargs.pop("redirect_uri_port", None) or 5000)
self.redirect_uri = f"http://{redirect_uri_domain}:{self.redirect_uri_port}/{redirect_uri_endpoint}"

# Time is expressed in seconds
self.timeout = float(kwargs.pop("timeout", None) or 60)


class DisplaySettings:
_default_template = """<!DOCTYPE html>
<html lang="en">
<head>
<title>{title}</title>
<style>
body {{
border: none;
box-sizing: border-box;
display: block;
font-family: "Segoe UI";
font-weight: 500;
line-height: 1.5;
padding: 50px 0 76px 0;
text-align: center;
}}
.content {{
padding: 30px 0 50px 0;
}}
h1 {{
color: {color};
font-size: 2.4rem;
margin: 1.7rem auto .5rem auto;
}}
p {{
color: #2f374f;
font-size: 1.2rem;
margin: .75rem 0 0 0;
}}
.btn {{
display: inline-block;
color: {color} !important;
text-decoration: none;
background-color: {background_color};
padding: 14px 24px;
border-radius: 8px;
font-size: 1em;
font-weight: 400;
margin: 50px 0 0 0;
}}
.btn:hover {{
color: {background_color} !important;
background-color: {color};
}}
@keyframes zoomText {{
from {{
opacity: 0;
transform: scale3d(0.9, 0.9, 0.9);
}}
50% {{
opacity: 1;
}}
}}
.content h1 {{
animation-duration: .6s;
animation-fill-mode: both;
animation-name: zoomText;
animation-delay: .2s;
}}
</style>
</head>
<body onload="window.open('', '_self', ''); window.setTimeout(close, {display_time})">
<div class="content">
<h1>{title}</h1>
<p>{information}</p>
</div>
<div class="more">
<a href="https://colin-b.github.io/httpx_auth/" class="btn" target="_blank" rel="noreferrer noopener" role="button">Documentation</a>
<a href="https://github.com/Colin-b/httpx_auth/blob/develop/CHANGELOG.md" class="btn" target="_blank" rel="noreferrer noopener" role="button">Latest changes</a>
</div>
</body>
</html>"""
_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,
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 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
Loading

0 comments on commit 0bd9b23

Please sign in to comment.