One place for hosting & domains

      аутентификации

      Настройка аутентификации на базе ключей SSH на сервере Linux


      Введение

      SSH или защищенная оболочка — это шифрованный протокол, используемый для администрирования и связи с серверами. При работе с сервером Linux вы, скорее всего, проведете больше всего времени в сеансах терминала с подключением к серверу через SSH.

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

      Как работают ключи SSH?

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

      Хотя пароли отправляются на сервер в безопасном режиме, обычно они недостаточно сложные и длинные, чтобы обеспечить надежную защиту против упорных злоумышленников, совершающих многократные атаки. Вычислительная мощность современных систем и автоматизированные скрипты позволяют достаточно легко взломать учетную запись методом прямого подбора пароля. Хотя существуют и другие методы усиления мер безопасности (fail2ban и т. д.), ключи SSH показали себя надежной и безопасной альтернативой.

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

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

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

      Открытый ключ выгружается на удаленный сервер, на который вы хотите заходить, используя SSH. Этот ключ добавляется в специальный файл ~/.ssh/authorized_keys в учетной записи пользователя, которую вы используете для входа.

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

      Создание ключей SSH

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

      Для этого мы можем использовать специальную утилиту ssh-keygen, которая входит в стандартный набор инструментов OpenSSH. По умолчанию она создает пару 2048-битных ключей RSA, что подходит для большинства сценариев использования.

      Сгенерируйте на локальном компьютере пару ключей SSH, введя следующую команду:

      ssh-keygen
      
      Generating public/private rsa key pair.
      Enter file in which to save the key (/home/username/.ssh/id_rsa):
      

      Утилита предложит вам выбрать место размещения генерируемых ключей. По умолчанию ключи хранятся в каталоге ~/.ssh внутри домашнего каталога вашего пользователя. Закрытый ключ будет иметь имя id_rsa, а соответствующий открытый ключ будет иметь имя id_rsa.pub.

      На этом этапе лучше всего использовать каталог по умолчанию. Это позволит вашему клиенту SSH автоматически находить ключи SSH при попытке аутентификации. Если вы хотите выбрать нестандартный каталог, введите его сейчас, а в ином случае нажмите ENTER, чтобы принять значения по умолчанию.

      Если ранее вы сгенерировали пару ключей SSH, вы можете увидеть следующий диалог:

      /home/username/.ssh/id_rsa already exists.
      Overwrite (y/n)?
      

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

      Created directory '/home/username/.ssh'.
      Enter passphrase (empty for no passphrase):
      Enter same passphrase again:
      

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

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

      • Закрытый ключ SSH (защищенная паролем часть) никогда не доступен через сеть. Парольная фраза используется только для расшифровки ключа на локальном компьютере. Это означает, что парольную фразу нельзя взломать через сеть методом прямого подбора.
      • Закрытый ключ хранится в каталоге с ограниченным доступом. Клиент SSH не принимает закрытые ключи, хранящиеся в каталогах, доступ к которым не ограничен. У самого ключа могут быть ограниченные разрешения (чтение и запись доступны только владельцу). Это означает, что другие пользователи системы не смогут создать уязвимость.
      • Для попытки взлома защищенного парольной фразой закрытого ключа SSH злоумышленнику уже необходим доступ к системе. Это означает, что у него уже должен быть доступ к учетной записи пользователя или учетной записи root. Если вы окажетесь в такой ситуации, парольная фраза может помешать злоумышленнику сразу же попасть на ваши другие серверы. Это может дать вам достаточно времени, чтобы создать и внедрить новую пару ключей SSH и запретить доступ с взломанным ключом.

      Поскольку закрытый ключ недоступен через сеть и защищен системой разрешений, доступ к этому файлу будет только у вас (и у пользователя root). Парольная фраза служит дополнительным уровнем защиты на случай взлома одной из этих учетных записей.

      Парольная фраза представляет собой необязательное дополнение. Если вы решите ее использовать, вам нужно будет вводить ее при каждом использовании соответствующего ключа (если вы не используете программный агент SSH, хранящий зашифрованный ключ). Мы рекомендуем использовать парольную фразу, но если вы не хотите ее задавать, вы можете просто нажать ENTER, чтобы пропустить этот диалог.

      Your identification has been saved in /home/username/.ssh/id_rsa.
      Your public key has been saved in /home/username/.ssh/id_rsa.pub.
      The key fingerprint is:
      a9:49:2e:2a:5e:33:3e:a9:de:4e:77:11:58:b6:90:26 username@remote_host
      The key's randomart image is:
      +--[ RSA 2048]----+
      |     ..o         |
      |   E o= .        |
      |    o. o         |
      |        ..       |
      |      ..S        |
      |     o o.        |
      |   =o.+.         |
      |. =++..          |
      |o=++.            |
      +-----------------+
      

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

      Как встроить открытый ключ при создании сервера

      Если вы создаете новый сервер DigitalOcean, вы можете автоматически встроить открытый ключ SSH в учетную запись root нового сервера.

      Внизу страницы создания дроплета есть опция для добавления ключей SSH на ваш сервер:

      Встраивание ключа SSH

      Если вы уже добавили файл открытого ключа в учетную запись DigitalOcean, вы сможете выбрать данную опцию (в примере выше указаны два существующих ключа: “Work key” и “Home key”). Чтобы встроить существующий ключ, нажмите на него, чтобы его выделить. Вы можете встроить несколько ключей на один сервер:

      Выбор ключа SSH

      Если в вашу учетную запись еще не выгружен открытый ключ SSH, или если вы хотите добавить новый ключ, нажмите кнопку “+ Add SSH Key”. При этом будет открыто диалоговое окно:

      Диалог ключа SSH

      Вставьте содержимое открытого ключа SSH в поле “SSH Key content”. Если вы сгенерировали ключи, используя указанный выше метод, вы можете получить содержимое открытого ключа на локальном компьютере, введя следующую команду:

      cat ~/.ssh/id_rsa.pub
      
      ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDNqqi1mHLnryb1FdbePrSZQdmXRZxGZbo0gTfglysq6KMNUNY2VhzmYN9JYW39yNtjhVxqfW6ewc+eHiL+IRRM1P5ecDAaL3V0ou6ecSurU+t9DR4114mzNJ5SqNxMgiJzbXdhR+j55GjfXdk0FyzxM3a5qpVcGZEXiAzGzhHytUV51+YGnuLGaZ37nebh3UlYC+KJev4MYIVww0tWmY+9GniRSQlgLLUQZ+FcBUjaqhwqVqsHe4F/woW1IHe7mfm63GXyBavVc+llrEzRbMO111MogZUcoWDI9w7UIm8ZOTnhJsk7jhJzG2GpSXZHmly/a/buFaaFnmfZ4MYPkgJD username@example.com
      

      Вставьте это значение в более крупное поле целиком. В поле “Comment (optional)” вы можете выбрать ярлык для данного ключа. Этот ярлык будет отображаться как имя ключа в интерфейсе DigitalOcean:

      Новый ключ SSH

      При создании дроплета выбранные вами открытые ключи SSH будут помещены в файл ~/.ssh/authorized_keys в учетной записи пользователя root. Это позволит вам входить на сервер с компьютера, используя ваш закрытый ключ.

      Как скопировать открытый ключ на ваш сервер

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

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

      Копирование открытого ключа с использованием SSH-Copy-ID

      Самый удобный способ скопировать открытый ключ на существующий сервер — использовать утилиту под названием ssh-copy-id. Поскольку этот метод очень простой, если он доступен, его рекомендуется использовать.

      Инструмент ssh-copy-id входит в пакеты OpenSSH во многих дистрибутивах, так что, возможно, он уже установлен на вашей локальной системе. Чтобы этот метод сработал, вы должны уже настроить защищенный паролем доступ к серверу через SSH.

      Для использования той утилиты вам нужно только указать удаленный хост, к которому вы хотите подключиться, и учетную запись пользователя, к которой у вас есть доступ через SSH с использованием пароля. Это учетная запись, куда будет скопирован ваш открытый ключ SSH.

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

      ssh-copy-id username@remote_host
      

      Вы можете увидеть следующее сообщение:

      The authenticity of host '111.111.11.111 (111.111.11.111)' can't be established.
      ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
      Are you sure you want to continue connecting (yes/no)? yes
      

      Это означает, что ваш локальный компьютер не распознает удаленный хост. Это произойдет при первом подключении к новому хосту. Введите «yes» и нажмите ENTER, чтобы продолжить.

      Затем утилита проведет сканирование локальной учетной записи для поиска ранее созданного ключа id_rsa.pub. Когда ключ будет найден, вам будет предложено ввести пароль учетной записи удаленного пользователя:

      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      username@111.111.11.111's password:
      

      Введите пароль (для безопасности вводимый текст не будет отображаться) и нажмите ENTER. Утилита подключится к учетной записи на удаленном хосте, используя указанный вами пароль. Затем содержимое ключа ~/.ssh/id_rsa.pub будет скопировано в основной каталог ~/.ssh удаленной учетной записи в файл с именем authorized_keys.

      Вы получите следующий результат:

      Number of key(s) added: 1
      
      Now try logging into the machine, with:   "ssh 'username@111.111.11.111'"
      and check to make sure that only the key(s) you wanted were added.
      

      Теперь ваш ключ id_rsa.pub выгружен в удаленную учетную запись. Теперь вы можете перейти к следующему разделу.

      Копирование открытого ключа с помощью SSH

      Если у вас нет ssh-copy-id, но вы активировали защищенный паролем доступ к учетной записи на вашем сервере через SSH, вы можете выгрузить ключи с помощью стандартного метода SSH.

      Для выполнения этой задачи мы можем вывести содержимое нашего открытого ключа SSH на локальный компьютер и передать его через соединение SSH на удаленный сервер. С другой стороны, мы можем подтвердить существование каталога ~/.ssh в используемой нами учетной записи и вывести переданные данные в файл authorized_keys в этом каталоге.

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

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

      cat ~/.ssh/id_rsa.pub | ssh username@remote_host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
      

      Вы можете увидеть следующее сообщение:

      The authenticity of host '111.111.11.111 (111.111.11.111)' can't be established.
      ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
      Are you sure you want to continue connecting (yes/no)? yes
      

      Это означает, что ваш локальный компьютер не распознает удаленный хост. Это произойдет при первом подключении к новому хосту. Введите «yes» и нажмите ENTER, чтобы продолжить.

      После этого вы увидите диалог, где нужно будет ввести пароль для учетной записи, к которой вы пытаетесь подключиться:

      username@111.111.11.111's password:
      

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

      Копирование открытого ключа вручную

      Если у вас нет защищенного паролем доступа SSH к вашему серверу, вам нужно будет выполнить вышеуказанную процедуру вручную.

      Содержимое файла id_rsa.pub нужно будет каким-то образом добавить в файл ~/.ssh/authorized_keys на удаленном компьютере.

      Чтобы вывести содержимое ключа id_rsa.pub, введите на локальном компьютере следующую команду:

      cat ~/.ssh/id_rsa.pub
      

      Вы увидите содержимое ключа, которое может выглядеть примерно так:

      ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqql6MzstZYh1TmWWv11q5O3pISj2ZFl9HgH1JLknLLx44+tXfJ7mIrKNxOOwxIxvcBF8PXSYvobFYEZjGIVCEAjrUzLiIxbyCoxVyle7Q+bqgZ8SeeM8wzytsY+dVGcBxF6N4JS+zVk5eMcV385gG3Y6ON3EG112n6d+SMXY0OEBIcO6x+PnUSGHrSgpBgX7Ks1r7xqFa7heJLLt2wWwkARptX7udSq05paBhcpB0pHtA1Rfz3K2B+ZVIpSDfki9UVKzT8JUmwW6NNzSgxUfQHGwnW7kj4jp4AT0VZk3ADw497M2G/12N0PPB5CnhHf7ovgy6nL1ikrygTKRFmNZISvAcywB9GVqNAVE+ZHDSCuURNsAInVzgYo9xgJDW8wUw2o8U77+xiFxgI5QSZX3Iq7YLMgeksaO4rBJEa54k8m5wEiEE1nUhLuJ0X/vh2xPff6SQ1BL/zkOhvJCACK6Vb15mDOeCSq54Cr7kvS46itMosi/uS66+PujOO+xt/2FWYepz6ZlN70bRly57Q06J+ZJoc9FfBCbCyYH7U/ASsmY095ywPsBo1XQ9PqhnN1/YOorJ068foQDNVpm146mUpILVxmq41Cj55YKHEazXGsdBIbXWhcrRf4G2fJLRcGUr9q8/lERo9oxRm5JFX6TCmj6kmiFqv+Ow9gI0x8GvaQ== demo@test
      

      Откройте удаленный хост, используя любой доступный метод. Например, если вы используете дроплет DigitalOcean Droplet как сервер, вы можете выполнить вход, используя веб-консоль на панели управления:

      Доступ к консоли DigitalOcean

      Когда вы получите доступ к учетной записи на удаленном сервере, вам нужно будет убедиться, что каталог ~/.ssh создан. При необходимости эта команда создаст каталог, а если каталог уже существует, команда ничего не сделает:

      mkdir -p ~/.ssh
      

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

      echo public_key_string >> ~/.ssh/authorized_keys
      

      В вышеуказанной команде замените public_key_string результатами команды cat ~/.ssh/id_rsa.pub, выполненной на локальном компьютере. Она должна начинаться с ssh-rsa AAAA....

      Если это сработает, вы можете попробовать установить аутентификацию без пароля.

      Аутентификация на сервере с использованием ключей SSH

      Если вы успешно выполнили одну из вышеописанных процедур, вы сможете войти на удаленный хост без пароля учетной записи для удаленного хоста.

      Базовый процесс выглядит аналогично:

      ssh username@remote_host
      

      Если вы подключаетесь к этому хосту первый раз (если вы используете указанный выше последний метод), вы сможете увидеть следующее:

      The authenticity of host '111.111.11.111 (111.111.11.111)' can't be established.
      ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
      Are you sure you want to continue connecting (yes/no)? yes
      

      Это означает, что ваш локальный компьютер не распознает удаленный хост. Введите «yes» и нажмите ENTER, чтобы продолжить.

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

      Если эта процедура будет выполнена успешно, переходите к следующему разделу, чтобы узнать, как полностью защитить сервер.

      Отключение аутентификации с помощью пароля на сервере

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

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

      Когда вышеуказанные условия будут выполнены, войдите на удаленный сервер с помощью ключей SSH с учетной записью root или с учетной записью с привилегиями sudo. Откройте файл конфигурации демона SSH:

      sudo nano /etc/ssh/sshd_config
      

      Найдите в файле директиву PasswordAuthentication. Она может быть помечена как комментарий. Удалите символ комментария в начале строки и установите значение «no». После этого вы потеряете возможность входа в систему через SSH с использованием паролей учетной записи:

      PasswordAuthentication no
      

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

      На компьютерах под управлением Ubuntu или Debian можно использовать следующую команду:

      sudo service ssh restart
      

      На компьютерах под управлением CentOS/Fedora этот демон носит имя sshd:

      sudo service sshd restart
      

      Выполнив этот шаг, вы успешно перенастроили демон SSH так, чтобы он реагировал только на ключи SSH.

      Заключение

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



      Source link

      Добавление аутентификации в ваше приложение с помощью Flask-Login


      Введение

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

      Анимированный файл gif с изображением приложения Flask и поля входа

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

      В этой статье мы затронем следующие вопросы:

      • Использование библиотеки Flask-Login для управления сеансами
      • Использование встроенной утилиты Flask для хэширования паролей
      • Добавление в приложение защищенных страниц для пользователей, не выполнивших вход
      • Использование Flask-SQLAlchemy для создания пользовательской модели
      • Создание форм регистрации и входа для создания учетных записей пользователей и входа
      • Вывод пользователям сообщений об ошибках, если что-то идет не так
      • Использование информации учетной записи пользователя для отображения на странице профиля

      Исходный код этого проекта доступен на GitHub.

      Предварительные требования

      Для этого обучающего модуля вам потребуется следующее:

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

      Здесь имеется схема, которая поможет понять, как будет выглядеть структура файлов проекта после завершения прохождения учебного модуля:

      .
      └── flask_auth_app
          └── project
              ├── __init__.py       # setup our app
              ├── auth.py           # the auth routes for our app
              ├── db.sqlite         # our database
              ├── main.py           # the non-auth routes for our app
              ├── models.py         # our user model
              └── templates
                  ├── base.html     # contains common layout and links
                  ├── index.html    # show the home page
                  ├── login.html    # show the login form
                  ├── profile.html  # show the profile page
                  └── signup.html   # show the signup form
      

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

      Шаг 1 — Установка пакетов

      Для нашего проекта нам потребуется три основных проекта:

      • Flask
      • Flask-Login: для обработки пользовательских сеансов после аутентификации
      • Flask-SQLAlchemy: для представления пользовательской модели и интерфейса с нашей базой данных

      Мы будем использовать SQLite, чтобы не устанавливать дополнительные зависимости для базы данных.

      Для начала мы создадим каталог проекта:

      Затем нам нужно будет перейти в каталог проекта:

      Если у нас нет среды Python, нам нужно будет ее создать. В зависимости от способа установки Python на вашем компьютере команды будут выглядеть примерно так:

      • python3 -m venv auth
      • source auth/bin/activate

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

      Выполните в своей виртуальной среде следующие команды для установки необходимых пакетов:

      • pip install flask flask-sqlalchemy flask-login

      Мы установили пакеты и теперь можем создать основной файл приложения.

      Шаг 2 — Создание главного файла приложения

      Для начала мы создадим каталог проекта:

      В первую очередь мы начнем работать над файлом __init__.py для нашего проекта:

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

      project/__init__.py

      from flask import Flask
      from flask_sqlalchemy import SQLAlchemy
      
      # init SQLAlchemy so we can use it later in our models
      db = SQLAlchemy()
      
      def create_app():
          app = Flask(__name__)
      
          app.config['SECRET_KEY'] = 'secret-key-goes-here'
          app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
      
          db.init_app(app)
      
          # blueprint for auth routes in our app
          from .auth import auth as auth_blueprint
          app.register_blueprint(auth_blueprint)
      
          # blueprint for non-auth parts of app
          from .main import main as main_blueprint
          app.register_blueprint(main_blueprint)
      
          return app
      

      Теперь у нас готов основной файл приложения, и мы можем начать добавление маршрутов.

      Шаг 3 — Добавление маршрутов

      Для наших маршрутов мы будем использовать два проекта. В основном проекте у нас будет главная страница (/) и страница профиля (/profile), открываемая после входа. Если пользователь попытается получить доступ к странице профиля без входа в систему, он будет направлен на маршрут входа.

      В нашем проекте auth у нас будут маршруты для получения страницы входа (/login) и страницы регистрации (/sign-up). Также у нас имеются маршруты для обработки запросов POST от обоих этих маршрутов. Наконец, у нас имеется маршрут выхода (/logout) для выхода активного пользователя из системы.

      Пока что мы определим login, signup и logout простыми возвратами. Мы вернемся к ним немного позднее и обновим их, добавив желаемые функции.

      Вначале создайте файл main.py для main_blueprint:

      project/main.py

      from flask import Blueprint
      from . import db
      
      main = Blueprint('main', __name__)
      
      @main.route('/')
      def index():
          return 'Index'
      
      @main.route('/profile')
      def profile():
          return 'Profile'
      

      Затем создайте файл auth.py для auth_blueprint:

      project/auth.py

      from flask import Blueprint
      from . import db
      
      auth = Blueprint('auth', __name__)
      
      @auth.route('/login')
      def login():
          return 'Login'
      
      @auth.route('/signup')
      def signup():
          return 'Signup'
      
      @auth.route('/logout')
      def logout():
          return 'Logout'
      

      В терминале вы можете задать значения FLASK_APP и FLASK_DEBUG:

      • export FLASK_APP=project
      • export FLASK_DEBUG=1

      Переменная среды FLASK_APP сообщает Flask, как загружать приложение. Она должна указывать на место создания create_app. Для наших целей мы будем использовать указатели на каталог project.

      Переменная среды FLASK_DEBUG активируется посредством присвоения ей значения 1. Это активирует отладчик, который будет отображать в браузере ошибки приложения.

      Убедитесь, что вы находитесь в каталоге flask_auth_app и запустите проект:

      Теперь у вас должна появиться возможность открыть в браузере пять возможных URL-адресов и увидеть возвращаемый текст, определенный в файлах auth.py и main.py.

      Например, если открыть адрес localhost:5000/profile, появится: Profile:

      Снимок экрана проекта с открытым адресом localhost:5000 в браузере

      Мы проверили поведение наших маршрутов и можем перейти к созданию шаблонов.

      Шаг 4 — Создание шаблонов

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

      • index.html
      • profile.html
      • login.html
      • signup.html

      Также у нас будет базовый шаблон, который будет содержать общий код для каждой из страниц. В данном случае базовый шаблон будет содержать ссылки навигации и общий макет страницы. Давайте создадим их сейчас.

      Для начала создайте каталог templates в каталоге project:

      • mkdir -p project/templates

      Затем создайте base.html:

      • nano project/templates/base.html

      Добавьте следующий код в файл base.html:

      project/templates/base.html

      <!DOCTYPE html>
      <html>
      
      <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <title>Flask Auth Example</title>
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css" />
      </head>
      
      <body>
          <section class="hero is-primary is-fullheight">
      
              <div class="hero-head">
                  <nav class="navbar">
                      <div class="container">
      
                          <div id="navbarMenuHeroA" class="navbar-menu">
                              <div class="navbar-end">
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
                                      Home
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
                                      Profile
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
                                      Login
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
                                      Sign Up
                                  </a>
                                  <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
                                      Logout
                                  </a>
                              </div>
                          </div>
                      </div>
                  </nav>
              </div>
      
              <div class="hero-body">
                  <div class="container has-text-centered">
                     {% block content %}
                     {% endblock %}
                  </div>
              </div>
          </section>
      </body>
      
      </html>
      

      Этот код создаст серию ссылок меню на каждую страницу приложения, а также область, где будет отображаться контент.

      Примечание. За кулисами мы используем Bulma для работы со стилями и макетом. Чтобы узнать больше о Bulma, ознакомьтесь с официальной документацией Bulma.

      Затем создайте файл templates/index.html:

      • nano project/templates/index.html

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

      project/templates/index.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Flask Login Example
      </h1>
      <h2 class="subtitle">
        Easy authentication and authorization in Flask.
      </h2>
      {% endblock %}
      

      Этот код создаст базовую страницу указателя с заголовком и подзаголовком.

      Затем создайте страницу templates/login.html:

      • nano project/templates/login.html

      Этот код генерирует страницу входа с полями Email и Password. Также имеется поле для отметки запоминания сеанса входа.

      project/templates/login.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Login</h3>
          <div class="box">
              <form method="POST" action="/login">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Your Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Your Password">
                      </div>
                  </div>
                  <div class="field">
                      <label class="checkbox">
                          <input type="checkbox">
                          Remember me
                      </label>
                  </div>
                  <button class="button is-block is-info is-large is-fullwidth">Login</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Создайте шаблон templates/signup.html:

      • nano project/templates/signup.html

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

      project/templates/signup.html

      {% extends "base.html" %}
      
      {% block content %}
      <div class="column is-4 is-offset-4">
          <h3 class="title">Sign Up</h3>
          <div class="box">
              <form method="POST" action="/signup">
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="email" name="email" placeholder="Email" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="text" name="name" placeholder="Name" autofocus="">
                      </div>
                  </div>
      
                  <div class="field">
                      <div class="control">
                          <input class="input is-large" type="password" name="password" placeholder="Password">
                      </div>
                  </div>
      
                  <button class="button is-block is-info is-large is-fullwidth">Sign Up</button>
              </form>
          </div>
      </div>
      {% endblock %}
      

      Затем создайте шаблон templates/profile.html:

      • nano project/templates/profile.html

      Добавьте этот код, чтобы создать простую страницу с закодированным заголовком, welcome Anthony:

      project/templates/profile.html

      {% extends "base.html" %}
      
      {% block content %}
      <h1 class="title">
        Welcome, Anthony!
      </h1>
      {% endblock %}
      

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

      После добавления шаблонов мы можем обновить выражения возврата в каждом из маршрутов, чтобы вместо текста возвращались шаблоны.

      Обновите файл main.py, изменив строку импорта и маршруты index и profile:

      project/main.py

      from flask import Blueprint, render_template
      ...
      @main.route('/')
      def index():
          return render_template('index.html')
      
      @main.route('/profile')
      def profile():
          return render_template('profile.html')
      

      Теперь мы обновим auth.py, изменив строку импорта и маршруты login и signup:

      project/auth.py

      from flask import Blueprint, render_template
      ...
      @auth.route('/login')
      def login():
          return render_template('login.html')
      
      @auth.route('/signup')
      def signup():
          return render_template('signup.html')
      

      После внесения этих изменений страница регистрации будет следующим образом при переходе в /sign-up:

      Страница регистрации в /signup

      Теперь вы должны видеть страницы /, /login и /profile.

      Пока что мы оставим /logout отдельно, потому что эта страница не отображает шаблон.

      Шаг 5 — Создание пользовательской модели

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

      Модели, созданные в Flask-SQLAlchemy, представляются классами, которые преобразуются в таблицу в базе данных. Атрибуты этих классов превратятся в столбцы этих таблиц.

      Давайте вместе создадим эту пользовательскую модель:

      Этот код создает пользовательскую модель со столбцами id, email, password и name:

      project/models.py

      from . import db
      
      class User(db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

      Мы создали пользовательскую модель и теперь можем перейти к настройке базы данных.

      Шаг 6 — Настройка базы данных

      Как указано в разделе «Предварительные требования», мы будем использовать базу данных SQLite. Мы можем создать базу данных SQLite самостоятельно, но сейчас используем для этого Flask-SQLAlchemy. Мы уже указали путь к базе данных в файле __init__.py, так что нам нужно просто указать Flask-SQLAlchemy создать базу данных на Python REPL.

      Если вы остановите приложение и откроете Python REPL, мы сможем создать базу данных, используя метод create_all для объекта db. Убедитесь, что вы все еще находитесь в виртуальной среде и в каталоге flask_auth_app.

      • from project import db, create_app
      • db.create_all(app=create_app()) # pass the create_app result so Flask-SQLAlchemy gets the configuration.

      Примечание. Если вы незнакомы с использованием интерпретатора Python, вы можете проконсультироваться с официальной документацией.

      Теперь вы видите файл db.sqlite в каталоге проекта. В этой базе данных будет наша пользовательская таблица.

      Шаг 7 — Настройка функции авторизации

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

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

      Создайте функцию и добавьте в ее конец переадресацию. В результате после успешной регистрации пользователь будет переадресован на страницу входа.

      Обновите файл auth.py, изменив строку import и реализовав signup_post:

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          # code to validate and add user to database goes here
          return redirect(url_for('auth.login'))
      

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

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

      Продолжим обновлять файл auth.py, добавляя элементы импорта и реализуя signup_post:

      auth.py

      from flask import Blueprint, render_template, redirect, url_for, request
      from werkzeug.security import generate_password_hash, check_password_hash
      from .models import User
      from . import db
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          email = request.form.get('email')
          name = request.form.get('name')
          password = request.form.get('password')
      
          user = User.query.filter_by(email=email).first() # if this returns a user, then the email already exists in database
      
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              return redirect(url_for('auth.signup'))
      
          # create a new user with the form data. Hash the password so the plaintext version isn't saved.
          new_user = User(email=email, name=name, password=generate_password_hash(password, method='sha256'))
      
          # add the new user to the database
          db.session.add(new_user)
          db.session.commit()
      
          return redirect(url_for('auth.login'))
      

      Примечание. Хранение паролей в формате обычного текста считается плохой практикой с точки зрения безопасности. Обычно для защиты паролей нужно использовать сложный алгоритм хэширования и шифрование паролей.

      Шаг 8 — Тестирование метода регистрации

      У нас готов метод регистрации, и теперь мы можем создать нового пользователя. Используйте форму для создания пользователя.

      Существует два способа проверить регистрацию: использовать инструмент просмотра БД для поиска строки, добавленную в таблицу, или попробовать зарегистрироваться с тем же адресом электронной почты, и если вы получите сообщение об ошибке, это будет означать, что первый адрес электронной почты был сохранен правильно. Используем этот подход.

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

      Вначале мы добавим элемент flash, выводимый до возврата на страницу регистрации.

      project/auth.py

      from flask import Blueprint, render_template, redirect, url_for, request, flash
      ...
      @auth.route('/signup', methods=['POST'])
      def signup_post():
          ...
          if user: # if a user is found, we want to redirect back to signup page so user can try again
              flash('Email address already exists')
              return redirect(url_for('auth.signup'))
      

      Чтобы добавить в шаблон мигающее сообщение, нужно добавить над формой этот код. Так сообщение будет выводиться непосредственно над формой.

      project/templates/signup.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}. Go to <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}">login page</a>.
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/signup">
      

      Поле регистрации с сообщением «Email address already exists. Go to login page» в темно-розовом поле

      Шаг 9 — Добавление метода входа

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

      После успешной проверки пароля мы знаем, что учетные данные пользователя верны, и мы можем разрешить ему вход в систему, используя Flask-Login. Вызывая login_user, Flask-Login создает сеанс этого пользователя, который сохраняется все время, пока пользователь остается в системе, и позволяет пользователю просматривать защищенные страницы.

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

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          # login code goes here
          return redirect(url_for('main.profile'))
      

      Теперь нам нужно убедиться, что учетные данные пользователя введены верно:

      project/auth.py

      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          email = request.form.get('email')
          password = request.form.get('password')
          remember = True if request.form.get('remember') else False
      
          user = User.query.filter_by(email=email).first()
      
          # check if the user actually exists
          # take the user-supplied password, hash it, and compare it to the hashed password in the database
          if not user or not check_password_hash(user.password, password):
              flash('Please check your login details and try again.')
              return redirect(url_for('auth.login')) # if the user doesn't exist or password is wrong, reload the page
      
          # if the above check passes, then we know the user has the right credentials
          return redirect(url_for('main.profile'))
      

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

      project/templates/login.html

      ...
      {% with messages = get_flashed_messages() %}
      {% if messages %}
          <div class="notification is-danger">
              {{ messages[0] }}
          </div>
      {% endif %}
      {% endwith %}
      <form method="POST" action="/login">
      

      Теперь мы можем указать, что пользователь успешно выполнил вход, но пользователю пока некуда входить. На этом этапе мы используем Flask-Login для управления сеансами пользователя.

      Прежде чем начать, нам потребуется несколько вещей для работы Flask-Login. Для начала добавьте UserMixin в пользовательскую модель. UserMixin добавит в модель атрибуты Flask-Login, чтобы Flask-Login мог с ней работать.

      models.py

      from flask_login import UserMixin
      from . import db
      
      class User(UserMixin, db.Model):
          id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
          email = db.Column(db.String(100), unique=True)
          password = db.Column(db.String(100))
          name = db.Column(db.String(1000))
      

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

      project/__init__.py

      ...
      from flask_login import LoginManager
      ...
      def create_app():
          ...
          db.init_app(app)
      
          login_manager = LoginManager()
          login_manager.login_view = 'auth.login'
          login_manager.init_app(app)
      
          from .models import User
      
          @login_manager.user_loader
          def load_user(user_id):
              # since the user_id is just the primary key of our user table, use it in the query for the user
              return User.query.get(int(user_id))
      

      В заключение мы можем добавить функцию login_user перед переадресацией на страницу профиля для создания сеанса:

      project/auth.py

      from flask_login import login_user
      from .models import User
      ...
      @auth.route('/login', methods=['POST'])
      def login_post():
          ...
          # if the above check passes, then we know the user has the right credentials
          login_user(user, remember=remember)
          return redirect(url_for('main.profile'))
      

      С помощью Flask-Login мы можем использовать маршрут /login. Когда все размещено правильно, вы увидите страницу профиля.

      Страница профиля с текстом «Welcome, Anthony!»

      Шаг 10 — Защита страниц

      Если ваше имя не Anthony, вы увидите, что ваше имя указано неправильно. Нам нужно, чтобы профиль отображал имя в базе данных. Вначале следует защитить страницу, а затем получить доступ к данным пользователя для получения его имени.

      Чтобы защитить страницу при использовании Flask-Login, мы добавим декоратор @login_requried между маршрутом и функцией. Это не даст пользователю, не выполнившему вход в систему, увидеть этот маршрут. Если пользователь не выполнил вход, он будет переадресован на страницу входа согласно конфигурации Flask-Login.

      Используя маршруты с декоратором @login_required, мы можем использовать объект current_user внутри функций. Этот объект current_user представляет пользователя из базы данных, и мы можем получить доступ ко всем атрибутам этого пользователя, используя точечную нотацию. Например, current_user.email, current_user.password, current_user.name и current_user.id будут возвращать реальные значения, хранящиеся в базе данных для пользователя, который выполнил вход в систему.

      Давайте используем имя текущего пользователя и отправим его в шаблон. Затем мы используем это имя и выведем его значение.

      project/main.py

      from flask_login import login_required, current_user
      ...
      @main.route('/profile')
      @login_required
      def profile():
          return render_template('profile.html', name=current_user.name)
      

      Затем в файле profile.html мы обновим страницу для отображения значения name:

      project/templates/profile.html

      ...
      <h1 class="title">
        Welcome, {{ name }}!
      </h1>
      

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

      Страница приветствия пользователя с именем пользователя, выполнившего вход в систему

      В заключение мы можем обновить представление выхода из системы. Мы можем вызвать функцию logout_user в маршруте выхода. Мы используем декоратор @login_required, потому что не имеет смысла выполнять выход для пользователя, который не выполнил вход.

      project/auth.py

      from flask_login import login_user, logout_user, login_required
      ...
      @auth.route('/logout')
      @login_required
      def logout():
          logout_user()
          return redirect(url_for('main.index'))
      

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

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

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

      templates/base.html

      ...
      <div class="navbar-end">
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.index') }}" class="navbar-item">
              Home
          </a>
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("main.profile') }}" class="navbar-item">
              Profile
          </a>
          {% endif %}
          {% if not current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.login') }}" class="navbar-item">
              Login
          </a>
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.signup') }}" class="navbar-item">
              Sign Up
          </a>
          {% endif %}
          {% if current_user.is_authenticated %}
          <a href="https://www.digitalocean.com/community/tutorials/{{ url_for("auth.logout') }}" class="navbar-item">
              Logout
          </a>
          {% endif %}
      </div>
      

      Главная страница с элементами навигации Home (Главная), Login (Вход) и Sign Up (Регистрация) в верхней части экрана

      Мы успешно создали приложение с аутентификацией.

      Заключение

      Мы использовали Flask-Login и Flask-SQLAlchemy для создания системы входа в наше приложение. Мы рассказали о том, как организовать аутентификацию пользователей посредством создания пользовательской модели и сохранения данных пользователя. Затем нам нужно было проверить правильность пароля пользователя, выполнив хэширование пароля из формы, и сравнив его с сохраненным в базе данных. В заключение мы добавили в приложение авторизацию, используя декоратор @login_required на странице профиля, чтобы пользователи могли видеть ее только после входа.

      Того, что мы создали в этом учебном модуле, будет достаточно для небольших приложений, но если вы хотите с самого начала использовать больше функций, подумайте об использовании библиотек Flask-User или Flask-Security, которые построены на базе библиотеки Flask-Login.



      Source link

      Установка и настройка SimpleSAMLphp для аутентификации SAML в Ubuntu 18.04


      Введение

      SimpleSAMLphp — это PHP-приложение для аутентификации с открытым исходным кодом, которое предоставляет поддержку SAML 2.0 в качестве поставщика сервиса (SP) или поставщика учетных записей (IdP).

      SAML (язык разметки подтверждений безопасности) — это защищенный механизм коммуникации на базе XML для обмена данными аутентификации и авторизации между организациями и приложениями. Часто он используется для реализации Web SSO (единый вход в систему). Это устраняет необходимость сохранения нескольких учетных данных для разных организаций. Проще говоря, вы можете использовать одну учетную запись, например имя пользователя и пароль, для доступа к нескольким приложениям.

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

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

      Предварительные требования

      • Один сервер Ubuntu 18.04, настроенный в соответствии с руководством по начальной настройке сервера Ubuntu 18.04, включая пользователя non-root user с привилегиями sudo и брандмауэр.
      • Apache, MySQL и PHP, установленные на сервере согласно руководству Установка Linux, Apache, MySQL, PHP (стек LAMP) в Ubuntu 18.04.
      • Доменное имя, настроенное так, чтобы указывать на ваш сервер. Информацию о том, как сделать так, чтобы домены указывали на дроплеты DigitalOcean, можно найти в руководстве Как создать указание на серверы имен DigitalOcean из общих реестров доменов.
      • Виртуальный хост, настроенный для домена с помощью директивы ServerName. Следуйте указаниям руководства по настройке виртуальных хостов Apache в Ubuntu 18.04 для настройки вашего доменного имени.
      • Сертификат Let’s Encrypt для домена, который вы настроили согласно руководству по обеспечению безопасности Apache с помощью Let’s Encrypt в Ubuntu 18.04.

      Шаг 1 — Загрузка и установка SimpleSAMLphp

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

      Войдите на сервер, если вы еще не сделали этого.

      Загрузите SimpleSAMLphp на веб-сайте проекта. SimpleSAMLphp всегда использует для последней стабильной версии программного обеспечения один и тот же URL-адрес. Это означает, что мы можем получить последнюю версию, введя следующую команду:

      • wget https://simplesamlphp.org/download?latest

      В результате будет загружен сжатый файл с именем download?latest, который содержит SimpleSAMLphp. Выполните извлечение содержимого файла с помощью команды tar:

      Файлы будут извлечены в новую директорию с именем simplesamlphp-1.x.y, где x.y — это текущий номер версии. Используйте команду ls для идентификации файла:

      Вы увидите отображаемое имя файла:

      Ouptut

      simplesamlphp-1.18.5

      Теперь скопируйте содержимое директории в /var/simplesamlphp​​​ с помощью команды cp. Обязательно замените номер версии на номер вашей версии:

      • sudo cp -a simplesamlphp-1.x.y/. /var/simplesamlphp/

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

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

      Существует несколько дополнительных пакетов программного обеспечения, которые требуются SimpleSAMLphp, включая расширения PHP для работы с XML, многобайтовыми строками, curl и LDAP. Также необходимо установить memcached. Установите все необходимо с помощью вашего диспетчера пакетов.

      Вначале обновите список пакетов:

      Затем выполните установку пакетов:

      • sudo apt install php-xml php-mbstring php-curl php-memcache php-ldap memcached

      После завершения установки перезапустите Apache для активации новых расширений PHP:

      • sudo systemctl restart apache2

      Теперь, когда SimpleSAMLphp установлен, давайте настроим Apache для обслуживания файлов.

      Шаг 2 — Настройка Apache для обслуживания SimpleSAMLphp

      Вы уже настроили домен и указали на сервер, а также настроили виртуальный хост для работы с HTTPS, обеспечив защиту Apache с помощью Let’s Encrypt. Давайте используем его для обслуживания SimpleSAMLphp.

      Единственная директория SimpleSAMLphp, которая должна быть видима в сети, — /var/simplesamlphp/www. Чтобы открыть для нее доступ из Интернета, измените файл конфигурации виртуального хоста SSL Apache для вашего домена.

      Если ваш файл конфигурации виртуального хоста имеет имя your_domain.conf, Let’s Encrypt создает новый файл конфигурации your_domain-le-ssl.conf​​​, который обрабатывает запросы HTTPS для вашего домена. Откройте файл конфигурации SSL с помощью следующей команды, чтобы отредактировать файл. Обязательно замените your_domain на актуальное имя файла:

      • sudo nano /etc/apache2/sites-available/your_domain-le-ssl.conf

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

      your_domain-le-ssl.conf’>/etc/apache2/sites-available/your_domain-le-ssl.conf

      <IfModule mod_ssl.c>
      <VirtualHost *:443>
              ServerName your_domain
      
              ServerAdmin webmaster@localhost
              DocumentRoot /var/www/html
      
              ErrorLog ${APACHE_LOG_DIR}/error.log
              CustomLog ${APACHE_LOG_DIR}/access.log combined
      
      SSLCertificateFile /etc/letsencrypt/live/your_domain/fullchain.pem
      SSLCertificateKeyFile /etc/letsencrypt/live/your_domain/privkey.pem
      Include /etc/letsencrypt/options-ssl-apache.conf
      </VirtualHost>
      </IfModule>
      

      Директива ServerName задает здесь базовый домен, который должен соответствовать этому определению виртуального хоста. Это должно быть доменное имя, для которого вы настроили сертификат SSL согласно информации в разделе предварительных требований. Давайте добавим директиву Alias, которая будет контролировать SimpleSAMLphp для всех URL-адресов, соответствующих https://your_domain/simplesaml/*. Сделайте это, добавив следующую строку в файл конфигурации:

      your_domain-le-ssl.conf’>/etc/apache2/sites-available/your_domain-le-ssl.conf

      ...
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
      
        Alias /simplesaml /var/simplesamlphp/www
      
      ...
      

      Это означает, что все URL-адреса, совпадающие с domain_name/simplesaml/*, будут направляться в директорию /var/simplesamlphp/www, предоставляя контроль SimpleSAMLphp.

      Далее мы предоставим доступ к директории /var/simplesamlphp/www, указав контроль доступа Require all granted​​​ для нее. Это позволит получить доступ к службе SimpleSAMLphp через Интернет. Сделайте это, добавив следующую строку в файл конфигурации:

      your_domain-le-ssl.conf’>/etc/apache2/sites-available/your_domain-le-ssl.conf

      ...
        Alias /simplesaml /var/simplesamlphp/www
        <Directory /var/simplesamlphp/www/>
            Require all granted
        </Directory>
      ...
      

      Сохраните и закройте файл. Перезапустите Apache для вступления изменений в силу:

      • sudo systemctl restart apache2

      Теперь, когда Apache настроен для обслуживания файлов приложения, давайте настроим SimpleSAMLphp.

      Шаг 3 — Настройка SimpleSAMLphp

      Далее нам необходимо внести несколько изменений в основную конфигурацию SimpleSAMLphp, размещенную в /var/simplesamlphp/config/config.php​​​. Откройте файл в своем редакторе:

      • nano /var/simplesamlphp/config/config.php

      Задайте пароль администратора, заменив в строке 'auth.adminpassword' значение по умолчанию 123​​ на более безопасный пароль. Этот пароль позволяет получить доступ к некоторым страницам в веб-интерфейсе вашей установки SimpleSAMLphp:

      /var/simplesamlphp/config/config.php

      . . .
      'auth.adminpassword'        => 'your_admin_password',
      . . .
      

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

      Вы можете использовать функцию OpenSSL rand для генерации случайной строки для использования в качестве строки соли. Откройте новый терминал, подключитесь к серверу еще раз и запустите следующую команду для получения этой строки:

      Опция -base64 32 гарантирует получение зашифрованной по алгоритму Base64 строки длиной 32 символа.

      Затем в файле конфигурации найдите запись 'secretsalt'​​​ и замените defaultsecretsalt​​​ на строку, которую вы сгнерировали:

      /var/simplesamlphp/config/config.php

      . . .
      'secretsalt' => 'your_generated_salt',
      . . .
      

      Затем задайте техническую контактную информацию. Эта информация будет доступна в генерируемых метаданных, а SimpleSAMLphp будет отправлять автоматически генерируемые отчеты об ошибке на заданный вами адрес электронной почты. Найдите следующий раздел:

      /var/simplesamlphp/config/config.php

      . . .
      'technicalcontact_name'     => 'Administrator',
      'technicalcontact_email'    => 'na@example.org',
      . . .
      

      Замените Administrator​​​ и na@example.org на соответствующие значения.

      Затем задайте часовой пояс, который вы хотите использовать. Найдите следующий раздел:

      /var/simplesamlphp/config/config.php

      . . .
      'timezone' => null,
      . . .
      

      Замените null​​​ на предпочитаемый часовой пояс из этого списка часовых поясов для PHP. Обязательно поместите значения в кавычки:

      /var/simplesamlphp/config/config.php

      . . .
      'timezone' => 'America/New_York',
      . . .
      

      Сохраните и закройте файл. Теперь вы можете получить доступ к сайту в браузере, указав в адресной строке https://your_domain/simplesaml​​​. Вы увидите следующий экран в браузере:

      веб-интерфейс simplesaml

      Чтобы убедиться, что ваша установка PHP соответствует всем требованиям SimpleSAMLphp для плавного запуска, выберите вкладку Конфигурация и нажмите ссылку Войти как администратор. Затем воспользуйтесь паролем администратора, заданным в файле конфигурации на шаге 3.

      После входа вы увидите список обязательных и дополнительных расширений PHP, которые используются SimpleSAMLphp. Убедитесь, что вы установили каждое расширение, за исключением predis/predis​​​:

      Все расширения установлены

      Если какие-либо обязательные компоненты отсутствуют, просмотрите это руководство и установите недостающие элементы, прежде чем продолжить.

      Также вы увидите ссылку, которая говорит Проверка работоспособности вашей установки SimpleSAMLphp. Нажмите эту ссылку для получения списка проверок, выполненных для вашей установки, чтобы убедиться, что они выполнены успешно.

      Теперь давайте перейдем к настройке источника аутентификации для SimpleSAMLphp.

      Шаг 4 — Настройка источника аутентификации

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

      Чтобы начать, выполните вход в учетную запись root MySQL:

      Вам будет предложено ввести пароль учетной записи root MySQL. Предоставьте нужные данные, чтобы продолжить.

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

      • CREATE DATABASE auth DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

      Теперь давайте создадим отдельного пользователя MySQL для работы исключительно в нашей базе данных auth. С точки зрения управления и безопасности рекомендуется использовать базы данных и учетные записи с одной функцией. Мы назовем пользователя authuser. Выполните следующую команду для создания пользователя, задайте пароль и предоставьте доступ к нашей базе данных auth. Не забудьте задать надежный пароль для нового пользователя базы данных.

      • GRANT ALL ON auth.* TO 'authuser'@'localhost' IDENTIFIED BY 'your_mysql_auth_user_password';

      Теперь создайте таблицу users, которая будет состоять из двух полей: username и password. Для дополнительной безопасности мы будем использовать функцию MySQL AES_ENCRYPT() для шифрования строки пароля, чтобы не сохранять пароли в текстовом формате. Эта функция шифрует строку и возвращает бинарную строку.

      • CREATE TABLE auth.users(username VARCHAR(30), password VARBINARY(30));

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

      • INSERT INTO auth.users(username, password) VALUES
      • ('user1', AES_ENCRYPT('user1pass','your_secret_key')),
      • ('user2', AES_ENCRYPT('user2pass','your_secret_key')),
      • ('user3', AES_ENCRYPT('user3pass','your_secret_key'));

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

      Нам нужно установить права, чтобы текущий экземпляр MySQL узнал о последних внесенных нами изменениях в права:

      Закройте командную строку MySQL с помощью следующей команды:

      Чтобы активировать функционал поставщика удостоверений в SimpleSAMLphp, нам нужно отредактировать файл /var/simplesamlphp/config/config.php. Существует несколько доступных способов, но поскольку это руководство посвящено поддержке SAML 2.0, мы будем использовать опцию enable.saml20-idp​​​. Для этого откройте /var/simplesamlphp/config/config.php​​​ и активируйте поддержку SAML 2.0:

      • nano /var/simplesamlphp/config/config.php

      Найдите следующий раздел файла и замените false​​ на true:

      /var/simplesamlphp/config/config.php

      ...
      'enable.saml20-idp' => true,
      ...
      

      Сохраните файл и выйдите из редактора.

      Теперь, когда у нас есть активированный поставщик удостоверений, нам нужно указать модуль аутентификации для использования. Поскольку у нас есть таблица пользователей в базе данных MySQL, мы будем использовать модуль аутентификации SQL. Откройте файл конфигурации authsources​​​:

      • nano /var/simplesamlphp/config/authsources.php

      Найдите следующий закомментированный блок:

      /var/simplesamlphp/config/authsources.php

      ...
          /*
          'example-sql' => array(
              'sqlauth:SQL',
              'dsn' => 'pgsql:host=sql.example.org;port=5432;dbname=simplesaml',
              'username' => 'simplesaml',
              'password' => 'secretpassword',
              'query' => 'SELECT uid, givenName, email, eduPersonPrincipalName FROM users WHERE uid = :username AND password = SHA2(CONCAT((SELECT salt FROM users WHERE uid = :username), :password),256);',
          ),
          */
      ...
      

      Этот код определяет подключение к базе данных и запрос, который SimpleSAMLphp может использовать для поиска пользователя в таблице базы данных с именем users. Нам нужно разкомментировать его и изменить запрос для поиска пользователя из нашей таблицы с помощью функции MySQL AES_DECRYPT(). Нам нужно предоставить функции AES_DECRYPT() тот же ключ, который мы использовали для шифрования паролей в запросе.

      Измените раздел файла, чтобы указать данные подключения к базе данных и запрос:

      /var/simplesamlphp/config/authsources.php

      ...
          'example-sql' => array(
              'sqlauth:SQL',
              'dsn' => 'mysql:host=localhost;port=5432;dbname=auth',
              'username' => 'authuser',
              'password' => 'your_mysql_auth_user_password',
              'query' => 'SELECT username FROM users WHERE username = :username AND AES_DECRYPT(password,"your_secret_key") = :password',
          ),
      ...
      

      Обязательно укажите секретный ключ, который вы задали, вместо your_secret_key.

      Сохраните и закройте файл. Давайте проверим нашего поставщика удостоверений.

      Шаг 5 — Тестирование поставщика удостоверений с помощью SAML 2.0 SP Demo

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

      Список настроенных источников аутентификации

      Нажмите example-sql, поскольку это ваш поставщик, настроенный на предыдущем шаге. Появится запрос на ввод имени пользователя и пароля. Введите данные для любого из трех тестовых пользователей, которых вы добавили в таблицу пользователей MySQL. Попробуйте использовать user1 с паролем user1pass.

      После успешной попытки входа вы увидите страницу SAML 2.0 SP Demo Example​​​:

      Успешная страница демо

      Если вы не можете выполнить вход и знаете, что пароль верный, убедитесь, что вы применяли один и тот же ключ для функции AES_ENCRYPT(), используемой при создании пользователя, и функции AES_DECRYPT(), которая использовалась при поиске пользователя.

      Теперь вы можете интегрировать SimpleSAMLphp в ваше приложение согласно документации SimpleSAMLphp API.

      Заключение

      Теперь у вас есть установленное и настроенное соответствующим образом приложение SimpleSAMLphp в Ubuntu 18.04 VPS. SimpleSAMLphp также позволяет использовать широкий набор вариантов пользовательской настройки интерфейса с помощью тем. Вы можете ознакомиться с документацией по использованию тем для получения дополнительной информации.



      Source link