From 9e579972ca68e1bc5adfc7dd875659ac0f21a0aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:38:37 +0000 Subject: [PATCH 1/2] Initial plan From 92d6a06a338f4a1f58adca770b9f3b05649384a9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:46:25 +0000 Subject: [PATCH 2/2] Default LOGTO_SKIP_SSL_VERIFY to true; update comment and docs Agent-Logs-Url: https://github.com/christianlouis/dmarq/sessions/8a17f133-904d-45c7-bc35-b3f5c1d2c97e Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> --- backend/app/core/config.py | 5 +++ backend/app/core/logto.py | 55 ++++++++++++++++++++++++++++++++ docs/deployment/configuration.md | 10 ++++++ 3 files changed, 70 insertions(+) diff --git a/backend/app/core/config.py b/backend/app/core/config.py index fda78de..f88c1a4 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -71,10 +71,15 @@ class Settings(BaseSettings): # LOGTO_APP_SECRET: the Client Secret of the same application. # LOGTO_REDIRECT_URI (optional): override the default callback URL. # Defaults to /api/v1/auth/callback. + # LOGTO_SKIP_SSL_VERIFY (optional): set to false to enable SSL certificate + # verification when connecting to the Logto OIDC endpoint. + # Defaults to true (verification disabled) to support + # self-signed certificates out of the box. LOGTO_ENDPOINT: Optional[str] = None LOGTO_APP_ID: Optional[str] = None LOGTO_APP_SECRET: Optional[str] = None LOGTO_REDIRECT_URI: Optional[str] = None + LOGTO_SKIP_SSL_VERIFY: bool = True @property def logto_configured(self) -> bool: diff --git a/backend/app/core/logto.py b/backend/app/core/logto.py index 372837e..a28f598 100644 --- a/backend/app/core/logto.py +++ b/backend/app/core/logto.py @@ -12,9 +12,11 @@ Provides: from __future__ import annotations import logging +import ssl from datetime import datetime, timedelta from typing import Optional +import aiohttp from fastapi import Request, Response from jose import JWTError, jwt from logto import IdTokenClaims, LogtoClient, LogtoConfig, PersistKey, Storage, UserInfoScope @@ -38,6 +40,59 @@ _SIGN_IN_SESSION_MAX_AGE = 600 # 10 minutes _SESSION_MAX_AGE = 86_400 # 24 hours +# ── SSL configuration for Logto SDK ────────────────────────────────────────── + + +def _apply_logto_ssl_patch() -> None: + """ + If ``LOGTO_SKIP_SSL_VERIFY`` is ``True``, monkey-patch ``aiohttp.ClientSession`` + so that every session created by the Logto SDK uses a non-verifying SSL connector. + + The Logto SDK creates its own ``aiohttp.ClientSession`` objects internally and + provides no mechanism to inject an SSL context. Replacing the class at module + level is the only way to propagate the setting without forking the SDK. + + **Scope note:** ``aiohttp`` is not used anywhere else in this application – only + the Logto SDK pulls it in. If additional code in this repository starts using + ``aiohttp`` directly, review whether those connections should also skip + verification before enabling this setting. + + .. warning:: + Disabling SSL verification removes protection against man-in-the-middle + attacks. Only enable this when connecting to a Logto instance that uses + a self-signed certificate that you control. + """ + if not settings.LOGTO_SKIP_SSL_VERIFY: + return + + logger.warning( + "LOGTO_SKIP_SSL_VERIFY is enabled – SSL certificate verification for " + "Logto OIDC connections is DISABLED. Use this only when your Logto " + "instance uses a self-signed certificate. Never enable this in a " + "production environment that faces the public internet." + ) + + ssl_ctx = ssl.create_default_context() + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + + _OriginalClientSession = aiohttp.ClientSession + + class _NoVerifyClientSession(_OriginalClientSession): # type: ignore[misc] + """``aiohttp.ClientSession`` subclass that disables SSL verification.""" + + def __init__(self, *args, **kwargs) -> None: # type: ignore[override] + if "connector" not in kwargs: + kwargs["connector"] = aiohttp.TCPConnector(ssl=ssl_ctx) + kwargs.setdefault("connector_owner", True) + super().__init__(*args, **kwargs) + + aiohttp.ClientSession = _NoVerifyClientSession # type: ignore[assignment] + + +_apply_logto_ssl_patch() + + # ── Cookie-backed Logto Storage ─────────────────────────────────────────────── diff --git a/docs/deployment/configuration.md b/docs/deployment/configuration.md index 9f0d256..8796fb8 100644 --- a/docs/deployment/configuration.md +++ b/docs/deployment/configuration.md @@ -34,6 +34,16 @@ DMARQ can be configured through: | `LOG_LEVEL` | Application logging level | `INFO` | `DEBUG`, `INFO`, `WARNING`, `ERROR` | | `CORS_ORIGINS` | Allowed CORS origins | `http://localhost:8000` | `https://dmarq.example.com` | +### Logto Authentication Settings + +| Variable | Description | Default | Example | +|----------|-------------|---------|---------| +| `LOGTO_ENDPOINT` | Base URL of your Logto instance | - | `https://your-tenant.logto.app` | +| `LOGTO_APP_ID` | Client ID of the Logto application | - | `your-app-id` | +| `LOGTO_APP_SECRET` | Client Secret of the Logto application | - | `your-app-secret` | +| `LOGTO_REDIRECT_URI` | Override the OAuth callback URL | Auto-detected | `https://dmarq.example.com/api/v1/auth/callback` | +| `LOGTO_SKIP_SSL_VERIFY` | Disable SSL certificate verification for connections to the Logto endpoint. **Only use this when your Logto instance uses a self-signed certificate that you control. Never enable in production environments.** | `true` | `true`, `false` | + ### IMAP Settings | Variable | Description | Default | Example |