Как реализовать OpenID Connect с несколькими провайдерами в Django?

Я пытаюсь реализовать несколько SSO (OpenID Connect) логинов в моем приложении, помимо обычного.

Текущие запросы провайдеров - Azure и Okta, но их будет больше. Для каждого крупного клиента, использующего мое приложение, я хочу иметь возможность предоставить ему пользовательский SSO логин, который он может настроить в панели администратора.

Все библиотеки, которые я пытался использовать для этого, либо используют settings.py и локальную аутентификацию django, либо они устарели.

Поток выглядит следующим образом:

Пользователь выбирает свою компанию и кнопку входа SSO -> Получает перенаправление на вход -> Я отправляю id клиента, секрет и т.д. (которые он ввел в панели администратора при регистрации sso соединения) -> В ответ я получаю токен с именем и email пользователя -> С помощью этой информации (email) я нахожу уже существующего пользователя в моей локальной базе данных и регистрирую его в системе -

Ваши собственные приложения обычно предпочитают доверять только одному провайдеру, а когда вы хотите задействовать несколько провайдеров, лучший способ - добавить свой собственный OIDC-провайдер локально, которому доверяют ваши приложения и API. А затем ваш OIDC-провайдер может доверять различным другим провайдерам. Как показано на рисунке ниже:

enter image description here

Если у вас SAAS-приложение, вы можете использовать workos.com для добавления SSO в ваше приложение вместо того, чтобы создавать его самостоятельно. Он поддерживает OIDC, SAML и многие другие провайдеры из коробки, а также имеет SDK для python

https://workos.com/docs/sso/guide/integrate-with-app/install-the-sdk-of-your-choice

  1. Пользователь выбирает свою компанию и кнопку входа SSO

OK, вы можете просто разместить кнопки на своем сайте.

  1. Получает перенаправление на вход в систему

Вы можете имплантировать /redirect конечную точку и обязательно сделать что-то для подготовки к получению информации о пользователе от провайдера OAuth2.

  1. Я отправляю идентификатор клиента, секрет и т.д. (которые они ввели в панели администратора при регистрации sso соединения)

Это также продолжение шага 2. но я не знаю, как подключиться к панели администратора Django. извините.

  1. В ответ я получаю токен с именем и электронной почтой пользователя

Используйте API информации о пользователе провайдера OAuth2. Таким образом, вы можете получить информацию о пользователе в том объеме, в котором вы хотите, если он ее предоставит.

  1. с этой информацией (email) я нахожу уже существующего пользователя в моей локальной базе данных и регистрирую его

    .

Просто напишите функцию с базой данных. это не сложно.

Думаю, этого достаточно для реализации. но that they can setup in the admin panel. Я не уверен, что вы можете настроить "уже сделанную" админ-панель Django. Это может быть трудно сделать.

У меня была похожая проблема, за исключением того, что мне нужна была поддержка нескольких поставщиков идентификационных данных для SAML, а также OIDC, и я решил ее следующим образом.

  • Я заметил, что реализация SAML SSO пакета django-social-auth поддерживает несколько "idp", основываясь на конфигурации в settings.py.

  • Исходя из этого, первым шагом было создание абстракции в модели Django, которую я назвал IdentityProvider (упуская терминологические различия между SAML и OIDC), и чистого аналога на языке Python под названием Idp, который является тонкой оберткой вокруг saml.SAMLIdentityProvider. Итак, в models.py:

    class IdentityProvider(models.Model):
        """
        SAML or OIDC Identity Provider for SSO. Based on the model exposed by
        PSA/python3-saml to multiple db-defined SSO setups.
        """
        ...
        real_backend = models.CharField("See below for what this is!!!!")
    

    и в других местах:

    class IdP(saml.SAMLIdentityProvider):
        def get_display_name(self, lang):
           ...
           return display_name
    
        def get_logo(self):
           ...
           return logo
    
  • Бэкенд SAML был дополнен MultiBackendMixin, чтобы позволить обнаруживать idps либо из конфигурации в settings.py, либо в IdentityProvider экземплярах:

    class SAMLSandboxAuth(MultiBackendMixin, saml.SAMLAuth):
       ...
    

    и аналогичный для OIDC:

    class OIDCSandboxAuth(MultiBackendMixin, base.BaseAuth):
       ...content based loosely on saml.SAMLAuth... 
    

Концептуально, все SSO выполняется через эти "SandboxAuths", и каждый из них отсылает к "реальному" бэкенду для фактической логики:

class SAMLAuth(saml.SAMLAuth):
   ...generic SAML backend...

class SAMLAuthMicrosoftAzureAD(SAMLAuth):
   ...Microsoft Azure AD SAML hacks for login_hint...

Обратите внимание, что я эффективно использовал saml.SAMLAuth один раз как SandboxAuth, и один раз как "настоящий" бэкенд!!! Случай с OIDC аналогичен, за исключением того, что, конечно, OIDCSandboxAuth полностью принадлежит мне, как указано выше.

Я должен отметить, что мой поток такой же, как и ваш, ИСКЛЮЧАЯ то, что на первом этапе пользователь должен указать свое имя входа. Я использую его для поиска IdentityProvider (и, следовательно, отображения имени и логотипа), который он должен использовать. "Настоящие" бэкенды предоставляют это имя как login_hint, если другой конец поддерживает его.

Вернуться на верх