FastAPI OAuth2 с ForgeRock: проблема с проверкой SSL-сертификата

Я работаю над реализацией аутентификации OAuth2 в приложении FastAPI, используя ForgeRock в качестве поставщика удостоверений. Эта установка находится во внутренней среде моей компании, и у меня есть необходимые сертификаты. Однако я сталкиваюсь с ошибкой проверки сертификата SSL при попытке аутентификации с помощью ForgeRock (или вызова конечной точки /auth/login):

[SSL: CERTIFICATE_VERIFY_FAILED] проверка сертификата не удалась: самостоятельно подписанный сертификат в цепочке сертификатов (_ssl.c:997)

FastAPI работает в контейнере, вот мой Dockerfile:

FROM xxx.com/xxx/python3.10.9-slim:1.0
WORKDIR /app
COPY ./ /app
COPY ./certs /etc/ssl/certs/ca-certificates
RUN chmod 644 /etc/ssl/certs/ca-certificates/*
RUN apt-get update && apt-get install -y ca-certificates
RUN update-ca-certificates
...

Сертификаты правильно перемещены в /etc/ssl/certs/ca-certificates.crt.

Вот мой упрощенный код FastAPI:

CA_BUNDLE_PATH = '/etc/ssl/certs/ca-certificates.crt'
os.environ['REQUESTS_CA_BUNDLE'] = CA_BUNDLE_PATH

ssl_context = ssl.create_default_context(cafile=CA_BUNDLE_PATH)
logging.debug(f"SSL context CA certificates: {ssl_context.get_ca_certs()}")

class CustomHttpxClient(httpx.AsyncClient):
    def __init__(self, *args, **kwargs):
        kwargs['verify'] = ssl_context
        super().__init__(*args, **kwargs)

oauth = OAuth()
oauth.register(
    name='forgerock',
    client_id='client-id',
    client_secret='secret',
    server_metadata_url='https://forgerock-login',
    client_kwargs = {
        'scope': 'openid profile email',
        'httpx_client': CustomHttpxClient()
    }
)

async def debug_session_state(request: Request):
    session = request.session
    state = session.get('state')
    logging.debug(f"Session state: {state}")

@app.get('/auth/login')
async def login(request: Request):
    try:
        redirect_uri = request.url_for('auth_callback')
        response = await oauth.forgerock.authorize_redirect(request, redirect_uri)
        request.session['state'] = response.state
        logging.debug(f"Stored state in session: {request.session['state']}")
        return response
    except Exception as e:
        logging.error(f"Error during authorization redirect: {e}")
        raise HTTPException(status_code=500, detail = "Internal Server Error")

@app.get('/auth/callback')
async def auth_callback(request: Request):
    await debug_session_state(request)
    try:
        state_in_session = request.session.get('state')
        state_in_request = request.query_params.get('state')
        logging.debug(f"State in session: {state_in_session}, State in request: {state_in_request}")
        
        if state_in_session != state_in_request:
            raise HTTPException(status_code=400, detail = "CSRF Warning! State not equal in request and response.")

        token = await oauth.forgerock.authorize_access_token(request)
        user = token.get('userinfo')
        return {'user': user}
    except Exception as e:
        logging.error(f"Callback Error: {e}")
        raise HTTPException(status_code=400, detail = "Authentication Failed")

Поэтому я загрузил сертификаты CA в собственный контекст SSL и использовал его с httpx.AsyncClient. Во всяком случае, я вижу это в журналах отладки:

ОТЛАДКА:httpx:load_verify_locations cafile='/usr/local/lib/python3.10/site-packages/certif/cacert.pem'

Кажется, контекст SSL отличается от указанного мной. Я пробовал разные методы передачи контекста SSL, но безрезультатно. Почему я не могу настроить контекст SSL?

Как включить TLS в gRPC-клиенте и сервере : 2
Как включить TLS в gRPC-клиенте и сервере : 2
Здравствуйте! 🙏🏻 Надеюсь, у вас все хорошо и добро пожаловать в мой блог.
Обновление драйверов Microsoft ODBC (с 17 до 18) для PHP
Обновление драйверов Microsoft ODBC (с 17 до 18) для PHP
Все знают, что PHP v7.4 потерял поддержку, и наши недавние старые приложения должны обновиться до PHP v8.x. ...
1
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В сообщении об ошибке упоминается httpx, а не requests.

httpx имеет собственный набор переменных Env, в данном случае SSL_CERT_FILE.

Будем надеяться, что переменная env var переопределит жестко запрограммированный CACERT из certify, что является серьезной проблемой при попытке использовать Python в корпоративной IS.

Ссылка: https://www.python-httpx.org/environment_variables/

Другие вопросы по теме