mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-29 11:09:27 -05:00
Security: Pass random 32 character string as OAuth request state and validate response
This commit is contained in:
parent
485237caf1
commit
9eee6227e8
@ -4,6 +4,7 @@ import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import secrets
|
||||
import tempfile
|
||||
import urllib
|
||||
import zipfile
|
||||
@ -11,6 +12,7 @@ from datetime import datetime
|
||||
from pathlib import Path
|
||||
from time import mktime
|
||||
from unicodedata import normalize
|
||||
from urllib.parse import parse_qs
|
||||
from urllib.parse import quote
|
||||
from urllib.parse import urlparse
|
||||
|
||||
@ -1714,13 +1716,34 @@ class UiSettingsView(GenericAPIView):
|
||||
ui_settings["auditlog_enabled"] = settings.AUDIT_LOG_ENABLED
|
||||
|
||||
if settings.GMAIL_OAUTH_ENABLED or settings.OUTLOOK_OAUTH_ENABLED:
|
||||
state = secrets.token_urlsafe(32)
|
||||
manager = PaperlessMailOAuth2Manager()
|
||||
if settings.GMAIL_OAUTH_ENABLED:
|
||||
ui_settings["gmail_oauth_url"] = manager.get_gmail_authorization_url()
|
||||
gmail_oauth_url = manager.get_gmail_authorization_url(state)
|
||||
# Validate the URL
|
||||
parsed_url_query = parse_qs(urlparse(gmail_oauth_url).query)
|
||||
if (
|
||||
parsed_url_query.get("state")
|
||||
and parsed_url_query.get("state")[0] != state
|
||||
):
|
||||
logger.error(
|
||||
f"Invalid oauth callback {gmail_oauth_url} for state {state}",
|
||||
)
|
||||
raise ValueError("State not found in authorization url")
|
||||
ui_settings["gmail_oauth_url"] = gmail_oauth_url
|
||||
if settings.OUTLOOK_OAUTH_ENABLED:
|
||||
ui_settings["outlook_oauth_url"] = (
|
||||
manager.get_outlook_authorization_url()
|
||||
)
|
||||
outlook_oauth_url = manager.get_outlook_authorization_url(state)
|
||||
# Validate the URL
|
||||
parsed_url_query = parse_qs(urlparse(outlook_oauth_url).query)
|
||||
if (
|
||||
parsed_url_query.get("state")
|
||||
and parsed_url_query.get("state")[0] != state
|
||||
):
|
||||
logger.error(
|
||||
f"Invalid oauth callback {outlook_oauth_url} for state {state}",
|
||||
)
|
||||
raise ValueError("State not found in authorization url")
|
||||
ui_settings["outlook_oauth_url"] = outlook_oauth_url
|
||||
|
||||
ui_settings["email_enabled"] = settings.EMAIL_ENABLED
|
||||
|
||||
|
@ -43,16 +43,17 @@ class PaperlessMailOAuth2Manager:
|
||||
def oauth_redirect_url(self) -> str:
|
||||
return f"{'http://localhost:4200/' if settings.DEBUG else settings.BASE_URL}mail" # e.g. "http://localhost:4200/mail" or "/mail"
|
||||
|
||||
def get_gmail_authorization_url(self) -> str:
|
||||
def get_gmail_authorization_url(self, state: str) -> str:
|
||||
return asyncio.run(
|
||||
self.gmail_client.get_authorization_url(
|
||||
redirect_uri=self.oauth_callback_url,
|
||||
scope=["https://mail.google.com/"],
|
||||
extras_params={"prompt": "consent", "access_type": "offline"},
|
||||
state=state,
|
||||
),
|
||||
)
|
||||
|
||||
def get_outlook_authorization_url(self) -> str:
|
||||
def get_outlook_authorization_url(self, state: str) -> str:
|
||||
return asyncio.run(
|
||||
self.outlook_client.get_authorization_url(
|
||||
redirect_uri=self.oauth_callback_url,
|
||||
@ -60,6 +61,7 @@ class PaperlessMailOAuth2Manager:
|
||||
"offline_access",
|
||||
"https://outlook.office.com/IMAP.AccessAsUser.All",
|
||||
],
|
||||
state=state,
|
||||
),
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user