Аутентификация, авторизация пользователей и единый вход (SSO) с использованием Django

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!

Привет, Хабр! Меня зовут Вячеслав Разводов, и я уже более 10 лет в IT. За это время мне удалось пройти путь от разработки на Delphi, разработки веб-сайтов на PHP-фреймворках до backend-разработки на Python. Этот материал является результатом моих усилий по систематизации знаний об SSO (единой системе идентификации).

В моей карьере присутствует период работы в бюджетной организации, подчиняющейся Министерству здравоохранения, где моя задача - разрабатывать информационные системы в формате веб-приложений. Условно системы можно сгруппировать:

  • регистры для специфических заболеваний;

  • инструменты для сбора статистических данных от медицинских работников;

  • системы для обработки отчетности;

Разработка новых, специализированных систем была регулярной задачей, с новыми проектами почти каждую неделю. Обычное техническое задание выглядело следующим образом:

Необходима система с возможностью загрузки файла формата xls. После загрузки система проводит проверки и позволяет юзеру скачать отчет об ошибках. Администратор может выгрузить общий отчет за выбранный период из данных, прошедших проверку.

Тем не менее, в процессе внедрения сталкивались с различными проблемами, особенно касающимися безопасности. Было критически важно обеспечить, чтобы доступ к системе осуществлялся пользователями исключительно через их уникальные учетные данные. Это необходимо для точной идентификации лиц, загружающих или скачивающих отчеты, а также для гарантии защиты данных от несанкционированного доступа.

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

В таких случаях, решением проблемы служит технология Единого Входа (SSO - Single Sign-On). Технология предоставляет возможность пользователям получать доступ к разным системам без повторного ввода логина и пароля. Например, врачу не нужно проходить процедуру авторизации в каждом отдельном веб-приложении при переключении между ними. Как это работает? И использовать такую технологию?

Сначала разберемся о механизмах аутентификация, авторизация пользователей на примере фреймворка Django. Потому что, приложение на Django будем интегрировать с SSO.

Основы аутентификации и авторизации в Django

Отвечаем на вопрос “Ты кто?” (аутентификация в Django)

Если спросить google ответ будет следующим:

Аутентификация — это процесс верификации идентичности пользователя, системы или приложения. Она часто включает в себя ввод имени пользователя и пароля, хотя может использовать и другие методы, такие как многофакторная аутентификация, биометрическая аутентификация и т.д.

Переведем на человеческий язык:

Аутентификация — это когда система сверяет предоставленные учетные данные, к примеру логин и пароль, с данными которые она хранит. В отделении банка, перед предоставлением вам услуг, работник просит предъявить ваш паспорт. После он внимательно сверяет ваше фото и лицо. Лицо и паспорт - это учетные данные, а процесс проверки сотрудником банка - аутентификация вас как клиента банка.

Аутентификация является важным элементом любой информационной системы, потому что:

  1. Безопасность и Конфиденциальность: Аутентификация является ключевым элементом защиты, препятствующим несанкционированному доступу к системам и данным. Она обеспечивает, что доступ к информации будет разрешен только авторизованным пользователям, тем самым предотвращая утечку конфиденциальных данных.

  2. Трассировка Действий: Действия аутентифицированные пользователей система может отслеживать, что способствует проведению аудита и мониторингу пользовательской активности.

  3. Контроль Доступа и Авторизация: Аутентификация лежит в основе процесса авторизации, который устанавливает доступность определенных ресурсов и действий для аутентифицированных пользователей.

В Django система аутентификации включает:

  • User Model: В фреймворке Django присуствует стандартная модель пользователя, которая содержит поля и методы, необходимые для управления учетными записями пользователей.

  • Middleware: Django использует middleware для обработки запросов и ответов. Middleware аутентификации добавляет пользователя к каждому запросу.

  • Views: Django предоставляет встроенные views для входа и выхода из системы, изменения и восстановления пароля.

Ключевую роль в процессе аутентификации играют - authentication backends. Authentication backends - это компоненты, которые определяют, каким образом происходит проверка учетных данных пользователя.

Django позволяет использовать несколько бэкендов аутентификации одновременно. Если стандартные методы аутентификации не удолетворяют требования разработчика. Можно написать собственный бэкенд. Для этого нужно создать класс, который наследует от django.contrib.auth.backends.BaseBackend и реализует методы authenticate (для проверки учетных данных) и get_user (для получения объекта пользователя).

Использование authentication backends в Django позволяет гибко подходить к процессу проверки подлинности пользователей, обеспечивая безопасность данных пользователей и удобство для разработчиков приложения.

Отвечаем на вопрос “Какие действия тебе доступны?” (авторизация в Django)

Авторизация — это процесс, который следует после аутентификации и определяет, какие действия или ресурсы доступны пользователю в системе. То есть это механизм, который определяет права и ограничения действий пользователей в системе. Выделим основные направления ее применения.

В первую очередь, как я уже отмечал, контроль доступа к ресурсам и ограничения действий пользователя. Контроль доступа к ресурсам - система будет проверять к каким файлам, страницам, функция имеет доступ пользователь на основе уровня прав. Ограничения действий, подразумевает какие операции (такие, как чтение, запись, удаление) разрешены пользователю на определенных ресурсах. Оба понятия близки по смыслу, поэтому я объединил их в одном пункте.

Второе направление применения авторизации - защита от несанкционированного доступа и соблюдение политик безопасности. Очевидно что с авторизацией в системе — никто не сможет получить доступ к защищённым ресурсам без ее прохождения.

Последнее направление — это трассировка и аудит. После авторизации пользователя система может вести журнал действий пользователя. Например, после авторизации в интернет-магазине, будут записываться все обращения к каталогу товаров, чтобы делать наиболее релевантные рекомендации.

Контроль доступа из первого пункта, тесно связан с авторизацией и включает в себя механизмы и методы, с помощью которых организации ограничивают доступ к своим ресурсам.

Рассмотрим виды контроля доступа. Отмечу, что я расположил в условном порядке от меньшего к большему, для упрощения усвоения информации.

Контроль доступа по атрибутам ABAC (Attribute-Based Access Control):

Доступ определяется на основе атрибутов пользователя, ресурса и окружающей среды. Django не включал в себя встроенную систему управления доступом на основе атрибутов ABAC как часть своего стандартного набора функций. Однако, благодаря гибкости и расширяемости Django, можно интегрировать ABAC, с помощью используя сторонние пакеты или разрабатывая собственное решение.

Примером стороннего решения является - django-rules. Собственные решения разрабатываются с применением паттерна декоратор. С алгоритмом в котором учитывают различные атрибуты и свойства для принятия решений о доступе к данным.

Контроль доступ по роли пользователя RBAC (Role-Based Access Control):

Пользователи получают роли, каждая роль имеет определенные разрешения. В терминалоги Django пользователи хранятся модели User, а роли это модель группы Group. Пользователи могут быть членами групп, и обе сущности могут иметь связанные с ними разрешения Permission. Важно разрешения могут быть присвоены как отдельным пользователям, так и группам.

Создания группы и присвоения разрешений:

from django.contrib.auth.models import Group, Permission

# Создание группы
editor_group, created = Group.objects.get_or_create(name='Редакторы')

# Получение разрешения
permission = Permission.objects.get(codename='change_article', name='Разрешено редактировать статьи')

# Присвоение разрешения группе
editor_group.permissions.add(permission)

Проверка разрешений во View:

from django.contrib.auth.decorators import permission_required

@permission_required('app_name.change_article')
def edit_article(request, article_id):
    # Логика обработки

Проверка разрешений в шаблонах:

{% if perms.app_name.change_article %}
  <a href="{% url 'edit-article' article.id %}">Edit Article</a>
{% endif %}

Контроль доступа на уровне объекта DAC (Discretionary Access Control):

Контроль доступа на уровне объекта (Object-Level Permissions) позволяет устанавливать дополнительные разрешения на конкретные объекты, с учетом общей политики безопасности. Например, автор статьи может иметь право редактировать свою статью, но не статьи других пользователей. В Django нет встроенной поддержки контроля доступа на уровне объекта для моделей, но можно реализовать это самостоятельно.

Добавляем метод в модель:

from django.contrib.auth.models import User

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)

    def can_edit(self, user: User):
        return self.author == user

Проверьте разрешение во View:

from django.http import HttpResponseForbidden

def edit_article(request, article_id):
    article = Article.objects.get(pk=article_id)
    
    if not article.can_edit(request.user):
        return HttpResponseForbidden("You don't have permission to edit this article.")

    # Логика редактирования статьи

Контроль доступа, при котором Владелец ресурса определяет политику доступа MAC (Mandatory Access Control):

Mandatory Access Control (MAC) – это система безопасности, где правила доступа к файлам и программам устанавливаются централизованно и пользователи не могут их изменять. MAC - строгий охранник, который следит за тем, чтобы каждый имел доступ только к тому, что разрешено высшими инструкциями, даже если владелец файла хочет дать кому-то доступ. Django не имеет встроенной поддержки для модели Mandatory Access Control в классическом понимании.

Что такое SSO и с чем его едят?

SSO (Single Sign-On) представляет собой технологическое решение в области безопасности и идентификации, которое позволяет пользователям входить в различные приложения и сервисы, используя только один набор учетных данных. Вместо того чтобы помнить пары логин, пароль для каждого отдельного приложения или веб-сервиса, пользователь может использовать одно имя пользователя и пароль для доступа к нескольким ресурсам.

Как это работает?

Технология SSO стоит на 2 китах. Первый кит - провайдер, это сервис который проводит процесс аутенфикации пользователя. Второй кит, или киты - это потребители, то есть приложения которые будут авторизовать пользователя. В классическом виде, это работает следующим образом:

  1. Пользователь пытается получить доступ к приложению. Приложение отправляет пользователя на страницу входа от провайдера.

  2. Провайдер проводит аутенфикацию пользователя, и возвращает приложению токен. В данном случаем под токеном подразумевается набор данных. В зависимости от протокола это может JWT или xml.

  3. Используя полученный токен, приложение обращается к провайдеру за информацией о пользователе, чтобы провести его авторизацию.

Использование технологии SSO, улучшает пользовательский опыт. Пользователям не нужно запоминать множество паролей для различных систем и приложений, что уменьшает сложность взаимодействия с сервисами. Вход в систему требуется только один раз, это экономит время пользователей. Снижается риска случая “Забыл Пароль”, потому пользователю нужно помнить только один пароль.

Административная панель провайдера SSO предлагает удобный способ эффективного управления всеми аспектами безопасности. Используя интерфейс панели, администратор имеет возможность реализовать ряд ключевых задач: от восстановления паролей пользователей до контроля их доступа к связанным системам, а также анализа пользовательской активности.

Где применяется?

Интеграция между различными веб-приложениями предоставляет пользователям удобный доступ к различным сервисам без повторной аутентификации. Это включает офисные инструменты, социальные сети и медиа, e-Commerce и образовательные ресурсы.

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

SSO на практике Keycloak

Разбираемся с протоколами SSO

Существует множество протоколов SSO, но давайте рассмотрим два наиболее популярных: OAuth2 и SAML. OAuth 2.0 - это открытый стандарт авторизации, предназначенный для предоставления третьим лицам ограниченного доступа к защищенным ресурсам пользователя. Провайдер Keycloak поддерживает OpenID Connect (OIDC) который является расширением протокола OAuth 2.0. SAML (Security Assertion Markup Language) - это стандарт обмена данными аутентификации и авторизации, основанный на XML.

OAuth 2.0 (OpenID Connect )

SAML (Security Assertion Markup Language)

Область применения

Веб, мобильные и настольные приложения.

Веб-приложения, особенно в корпоративных средах.

Преимущества

Гибкость, широко распространен, поддерживает различные типы токенов.

Поддерживает одиночный вход (Single Sign-On), безопасен, самовыполняемый (не требует внешних запросов для аутентификации).

Использование

Когда необходимо предоставить сторонним приложениям доступ к ресурсам пользователя без раскрытия учетных данных пользователя.

Когда необходимо обеспечить доступ к нескольким системам в рамках одной организации с использованием единой учетной записи.

OAuth 2.0 обладает лучшей масштабируемостью и гибкостью благодаря своему простому API и поддержке различных типов токенов. Но SAML предлагает более высокий уровень защиты за счет использования XML и цифровых подписей.

Выбор стандарта зависит от конкретных сценариев использования: OAuth 2.0 подходит для мобильных и настольных приложений, в то время как SAML лучше всего подходит для корпоративных веб-приложений.

Разворачиваем Keycloak (провайдер SSO)

В качестве провайдера SSO будем использовать Keycloak. Keycloak - это открытое программное обеспечение для управления и удостоверением личности. Он предоставляет надежное и гибкое решение для аутентификации, авторизации и управления правами доступа пользователей в приложениях и сервисах. Keycloak поддерживает множество протоколов аутентификации, включая SAML и OpenID Connect, что делает его мощным инструментом для реализации единого входа SSO.

Запускать Keycloak будем в Docker, для этого создаем файл docker-compose.yaml.

# deploy/docker-compose.yaml
version: '3.1'

services:
  keycloak:
    image: jboss/keycloak # *для ARM: sleighzy/keycloak:16.1.0-arm64
    environment:
      KEYCLOAK_USER: admin_key
      KEYCLOAK_PASSWORD: admin_key
    ports:
      - "8080:8080"

*Образ sleighzy/keycloak:16.1.0-arm64 - это не официальная сборка, я использовал его для запуска Keycloak на Macbook Pro на M2. Рекомендую использовать официальный образ jboss/keycloak.

После запуска контейнера, зайдем в панели управления, открыв в веб-браузере следующий URL (http://localhost:8080/auth) (рис. 1 ).

Рис.1. Приветственная страница Keycloak
Рис.1. Приветственная страница Keycloak

Выбираем “Administration Console” и попадаем на страницу авторизации в административной панели. Вводим логин/пароль который указывали в директивах KEYCLOAK_USER/KEYCLOAK_PASSWORD.

Создадим отдельный Reaml для нашей тестовой интеграции с Django. Realm — это пространство, которое включает в себя пользователей, клиентов, роли и другие конфигурационные элементы. Выберите меню "Master" Realm, и нажмите "Add Realm" (рис. 2).

Рис. 2. Меню добавления нового Realm
Рис. 2. Меню добавления нового Realm

В открывшемся окне, заполняем поле “Name” - название нового Realm (рис. 3). В моем случае я назову его “Django Integration”.

Рис. 3. Создаем новый Ream
Рис. 3. Создаем новый Ream

После создания Reaml, переходим на страницу добавления Clients (рис.4). Клиенты представляют собой приложения, которые будут использовать Keycloak для аутентификации.

Рис.4. Страница Clients
Рис.4. Страница Clients

На странице создания клиента (рис. 5) в поле Client ID, вводите произвольное название клиента. НО запомните его, оно понадобится дальнейших шагах.

Рис. 5. Страница создания клиента
Рис. 5. Страница создания клиента

В списке Client Protocol - выбираем openid-connect, как упоминалось ранее, это протокол основанный на OAuth 2.0.

Root URL для клиента в Keycloak - это базовый URL, который используется при формировании абсолютных URL в аутентификационных запросах и ответах. В моем случае, это локально запущенная Django на порту 8010. Этот параметр критически важен для обеспечения того, чтобы переадресации, инициированные Keycloak, корректно вели к нужным точкам входа вашего приложения.

Вот зачем это нужно:

  1. Формирование URL в аутентификации:

    Когда Keycloak перенаправляет пользователя на страницу аутентификации, он должен указать точный URL-адрес, на который пользователь будет возвращен после успешной аутентификации. Этот URL формируется на основе Root URL.

  2. Управление перенаправлениями:

    Root URL также используется для определения, на какой URL будет перенаправлен пользователь в случае успешной аутентификации или в случае ошибки. Например, если пользователь нажимает "Забыли пароль?" и запрашивает сброс пароля, Keycloak будет использовать Root URL для определения, куда перенаправить пользователя после этой операции.

  3. Обработка перенаправлений в клиентской стороне:

    Когда пользователь возвращает в ваше приложение после успешной аутентификации, клиент должен правильно обработать этот URL и продолжить работу с аутентифицированным пользователем.

Допустим, пользователь пытается получить доступ к нашему сайту, но не прошел аутентификацию. В этом случае приложение перенаправит его на Keycloak для аутентификации. После успешного прохождения аутентификации, Keycloak перенаправит пользователя обратно на наш сайт, вместе с токеном. Root URL в этом контексте определяет конкретный URL-адрес на нашем сайте, куда будет направлен токен.

После добавления Client, нас перенаправляет на страницу настройки Client (рис. 6).

Рис. 6. Страница настроек Client
Рис. 6. Страница настроек Client

В настройке Client нужно выбрать Access Type. Keycloak предлагает три различных режима "Access Type" для клиентов:

  1. Public:

    • В этом режиме клиент считается "публичным" и не имеет секретного ключа.

    • Клиент не может обмениваться кодами авторизации на токены безопасности, так как он не имеет секрета для подписи запросов.

    • Однако он может быть использован для аутентификации пользователей внутри браузера, например, в SPA-приложениях.

  2. Confidential:

    • В этом режиме клиент считается "конфиденциальным" и имеет секретный ключ.

    • Клиент может обмениваться кодами авторизации на токены безопасности с использованием своего секрета.

    • Обычно используется для бэкенд-приложений, где секрет ключа хранится в безопасном месте.

  3. Bearer-only:

    • Клиент считается "только-для-носителей" и не способен обмениваться кодами авторизации.

    • В этом режиме клиент принимает только аутентификационные токены в заголовках HTTP запросов.

    • Обычно используется для API, которые ожидают, что пользователь будет аутентифицирован до того, как он сможет воспользоваться ресурсами.

Выбор режима "Access Type" зависит от типа вашего клиента и какие действия он должен выполнять в системе. Например, веб-приложение может использовать "Confidential" для обмена кодами авторизации, тогда как API, возможно, будет настроен как "Bearer-only", ожидая токены в заголовках запросов.

Реализация интеграции на стороне Django, непосредственно зависит от выбора режима "Access Type".

Реализация интеграции на стороне Django, непосредственно зависит от выбора режима "Access Type".

Confidential:

При этом режиме при входе на наш сайт, пользователь редиректится на страницу входа от Keycloak. После успешной аутенфикации, возвращается на Valid Redirect URLs с токеном, по которому бэкенд сайта сможет получить данные пользователя. Необходим когда сайт, доступен в Интернете.

Bearer-only

При это режиме, данные пользователя уже доступны в Headers запроса пользователя. В данном случае можно RemoteUserBackend. RemoteUserBackend предназначен для аутентификации пользователей с использованием HTTP заголовков, предоставляемых веб-сервером, таких как REMOTE_USER. Такой вариант является, не безопасным, но идеально подойдет для корпоративных систем, когда доступ к сервисам осуществляется в рамках закрытой сети.

В поле Valid Redirect URLs изменяем на http://localhost:8010/keycloak_callback/.

Нажимаем кнопку “Save” и после сохранения рядом с вкладкой “Settings” появится вкладка “Credentials”. Если выбираем Confidential в Access Type, из вкладки “Credentials” необходимо копировать значение поля Secret. Этот Secret клиента необходимо будет сохранить в бэкенде приложения.

Переходим, в раздел Users чтобы добавить пользователя.

Рис. 7. Добавление пользователя
Рис. 7. Добавление пользователя

Вводим данные учетной записи пользователя и пароль.

Рис. 8. Добавление нового пользователя
Рис. 8. Добавление нового пользователя

Нажимаем кнопку “Save”, и переходим во вкладку Credentials, чтобы задать пароль.

Рис. 9. Задание пароля в данных пользователя
Рис. 9. Задание пароля в данных пользователя

Keycloak провайдер готов к использованию. Теперь можно приступить к разработке интеграций с бэкендом на Django.

Интеграция SSO с Django

Хочу подчеркнуть, что приведенные ниже примеры предназначены исключительно для лучшего понимания внутреннего механизма интеграции Keycloak и Django. В реальных проектах рекомендуется использовать библиотеку django_keycloak. В данной статье не рассматривается применение этой библиотеки.

Описание взаимодействия Django и Keycloak

Прежде чем, переходить к созданию интеграции между Django и Keycloak, предлагаю обсудить план действий. В виде схемы алгоритм взаимодействия отображен на рис.10.

Рис. 10. Схема взаимодействия между сайтом на Django и Keycloak
Рис. 10. Схема взаимодействия между сайтом на Django и Keycloak

Шаг 1. Не авторизованный пользователь попадает на страницу /login. Здесь будет только 1 кнопка, “

Источник: https://habr.com/ru/articles/787040/


Интересные статьи

Интересные статьи

Часть 1. Часть 2. Часть 3. Всем привет! В новой части мы рассмотрим использование JSFFI. Читать дальше →
Автор статьи, перевод которой мы публикуем, предлагает прекратить писать собственный код для аутентификации пользователей. Он полагает, что пришло время внедрять более безопасные реше...
История произошла в Telegram-канале БК00010, участником был я. Возник вопрос: как писать программы? Эмулятор не поддерживает запись дисков, поэтому использовать ассемблер в эму...
В современных x86 процессорах Intel, конвеер можно разделить на 2 части: Front End и Back End. Front End отвечает за загрузку кода из памяти и его декодирование в микрооперации. Back End о...
Добрый день, уважаемые коллеги! Я являюсь пользователем популярного платежного сервиса системы PayPal. Также, по совместительству, являюсь специалистом по технической безопасности в области защи...