add fallback
This commit is contained in:
parent
7e04edbc48
commit
fa34e459cb
5 changed files with 55 additions and 6 deletions
|
|
@ -6,6 +6,8 @@ import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
from utils.http_fallback import request_with_ssl_fallback
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
CACHE_KEY_TEMPLATE = "proxy_upstream_openapi_schema_{service}"
|
CACHE_KEY_TEMPLATE = "proxy_upstream_openapi_schema_{service}"
|
||||||
|
|
@ -37,7 +39,7 @@ def _fetch_service_schema(service, base_url, schema_path):
|
||||||
|
|
||||||
url = f"{base_url.rstrip('/')}{schema_path}"
|
url = f"{base_url.rstrip('/')}{schema_path}"
|
||||||
try:
|
try:
|
||||||
response = requests.get(url, timeout=FETCH_TIMEOUT_SECONDS)
|
response = request_with_ssl_fallback("GET", url, timeout=FETCH_TIMEOUT_SECONDS)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
schema = response.json()
|
schema = response.json()
|
||||||
except (requests.RequestException, ValueError) as exc:
|
except (requests.RequestException, ValueError) as exc:
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ from django.utils.decorators import method_decorator
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
|
from utils.http_fallback import request_with_ssl_fallback
|
||||||
|
|
||||||
# Headers that must not be copied verbatim between hops (RFC 7230 6.1) plus
|
# Headers that must not be copied verbatim between hops (RFC 7230 6.1) plus
|
||||||
# framing headers that HttpResponse recomputes itself.
|
# framing headers that HttpResponse recomputes itself.
|
||||||
HOP_BY_HOP_HEADERS = {
|
HOP_BY_HOP_HEADERS = {
|
||||||
|
|
@ -54,9 +56,9 @@ class ServiceProxyView(View):
|
||||||
target_url = f"{target_url}?{query_string}"
|
target_url = f"{target_url}?{query_string}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
upstream = requests.request(
|
upstream = request_with_ssl_fallback(
|
||||||
method=request.method,
|
request.method,
|
||||||
url=target_url,
|
target_url,
|
||||||
headers=_incoming_headers(request),
|
headers=_incoming_headers(request),
|
||||||
data=request.body,
|
data=request.body,
|
||||||
timeout=settings.SERVICE_REQUEST_TIMEOUT,
|
timeout=settings.SERVICE_REQUEST_TIMEOUT,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from httpx import Request
|
||||||
from utils.clients.gooyal_accounts_client import AuthenticatedClient
|
from utils.clients.gooyal_accounts_client import AuthenticatedClient
|
||||||
from utils.clients.gooyal_accounts_client.models import Account
|
from utils.clients.gooyal_accounts_client.models import Account
|
||||||
from utils.clients.gooyal_accounts_client.api.users import (users_api_users_details_retrieve)
|
from utils.clients.gooyal_accounts_client.api.users import (users_api_users_details_retrieve)
|
||||||
|
from utils.http_fallback import request_with_ssl_fallback, resolve_verify_ssl
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ def login_as_client_credentials():
|
||||||
}
|
}
|
||||||
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
|
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
|
||||||
|
|
||||||
response = requests.post(f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
|
response = request_with_ssl_fallback('POST', f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
|
||||||
data=data,
|
data=data,
|
||||||
auth=auth)
|
auth=auth)
|
||||||
print(response.content)
|
print(response.content)
|
||||||
|
|
@ -57,7 +58,9 @@ def log_response(response):
|
||||||
|
|
||||||
def get_client():
|
def get_client():
|
||||||
access_token = login_as_client_credentials()['access_token']
|
access_token = login_as_client_credentials()['access_token']
|
||||||
|
verify_ssl = resolve_verify_ssl(settings.ACCOUNTS_BASE_PUBLIC_URL)
|
||||||
client = AuthenticatedClient(base_url=settings.ACCOUNTS_BASE_PUBLIC_URL, token=access_token,
|
client = AuthenticatedClient(base_url=settings.ACCOUNTS_BASE_PUBLIC_URL, token=access_token,
|
||||||
|
verify_ssl=verify_ssl,
|
||||||
httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}},
|
httpx_args={"event_hooks": {"request": [log_request], "response": [log_response]}},
|
||||||
)
|
)
|
||||||
return client
|
return client
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ from utils.clients.gooyal_advertising_client.api.crm.crm_application_tickets_lis
|
||||||
from utils.clients.gooyal_advertising_client.api.suggestions.suggestions_suggest_list import sync as suggestions_suggest_list_sync
|
from utils.clients.gooyal_advertising_client.api.suggestions.suggestions_suggest_list import sync as suggestions_suggest_list_sync
|
||||||
from utils.clients.gooyal_advertising_client.models.paginated_ticket_list import PaginatedTicketList
|
from utils.clients.gooyal_advertising_client.models.paginated_ticket_list import PaginatedTicketList
|
||||||
from utils.clients.gooyal_advertising_client.models.paginated_suggestion_list import PaginatedSuggestionList
|
from utils.clients.gooyal_advertising_client.models.paginated_suggestion_list import PaginatedSuggestionList
|
||||||
|
from utils.http_fallback import request_with_ssl_fallback, resolve_verify_ssl
|
||||||
|
|
||||||
|
|
||||||
def login_as_client_credentials():
|
def login_as_client_credentials():
|
||||||
|
|
@ -27,7 +28,8 @@ def login_as_client_credentials():
|
||||||
}
|
}
|
||||||
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
|
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
|
||||||
|
|
||||||
response = requests.post(
|
response = request_with_ssl_fallback(
|
||||||
|
'POST',
|
||||||
f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
|
f'{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/',
|
||||||
data=data,
|
data=data,
|
||||||
auth=auth,
|
auth=auth,
|
||||||
|
|
@ -56,9 +58,11 @@ def log_response(response):
|
||||||
|
|
||||||
def get_client():
|
def get_client():
|
||||||
access_token = login_as_client_credentials()['access_token']
|
access_token = login_as_client_credentials()['access_token']
|
||||||
|
verify_ssl = resolve_verify_ssl(settings.ADVERTISING_BASE_PUBLIC_URL)
|
||||||
client = AuthenticatedClient(
|
client = AuthenticatedClient(
|
||||||
base_url=settings.ADVERTISING_BASE_PUBLIC_URL,
|
base_url=settings.ADVERTISING_BASE_PUBLIC_URL,
|
||||||
token=access_token,
|
token=access_token,
|
||||||
|
verify_ssl=verify_ssl,
|
||||||
httpx_args={
|
httpx_args={
|
||||||
'event_hooks': {
|
'event_hooks': {
|
||||||
'request': [log_request],
|
'request': [log_request],
|
||||||
|
|
|
||||||
38
utils/http_fallback.py
Normal file
38
utils/http_fallback.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import urllib3
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
|
||||||
|
|
||||||
|
def request_with_ssl_fallback(method, url, **kwargs):
|
||||||
|
"""Issue a request; if it fails purely due to a TLS/SSL error (e.g. an
|
||||||
|
expired upstream certificate), retry the same request with certificate
|
||||||
|
verification disabled. Still encrypted, but no longer authenticates the
|
||||||
|
server -- only safe for known internal/staging hosts, never for
|
||||||
|
arbitrary user-supplied URLs."""
|
||||||
|
try:
|
||||||
|
return requests.request(method, url, **kwargs)
|
||||||
|
except requests.exceptions.SSLError:
|
||||||
|
logger.warning("TLS verification failed for %s; retrying with verification disabled", url)
|
||||||
|
return requests.request(method, url, **{**kwargs, "verify": False})
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_verify_ssl(base_url, timeout=5):
|
||||||
|
"""Probe whether `base_url` currently presents a valid TLS certificate.
|
||||||
|
For callers stuck building an httpx-based client up front (e.g. the
|
||||||
|
generated SDK clients' `verify_ssl=`), whose requests happen lazily and
|
||||||
|
can't be retried after the fact."""
|
||||||
|
if not base_url.startswith("https://"):
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
requests.head(base_url, timeout=timeout)
|
||||||
|
return True
|
||||||
|
except requests.exceptions.SSLError:
|
||||||
|
logger.warning("TLS verification failed for %s; disabling verification for this client", base_url)
|
||||||
|
return False
|
||||||
|
except requests.exceptions.RequestException:
|
||||||
|
return True
|
||||||
Loading…
Add table
Reference in a new issue