ustu / lectures.www

Основы Веб программирования
http://lectureswww.readthedocs.io
GNU General Public License v3.0
41 stars 15 forks source link

Авторизация в Pyramid #17

Open uralbash opened 7 years ago

uralbash commented 7 years ago

http://lectureswww.readthedocs.io/6.www.sync/3.framework/pyramid/10.security.html

RaccoonBoyG commented 7 years ago

acl в ресурсах from pyramid.security import Allow from pyramid.security import Everyone

class Blog(object): pass

blog = Blog()

blog.acl = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] форма авторизации

import colander import deform from jinja2 import Environment, FileSystemLoader

env = Environment(loader=FileSystemLoader('templates'))

class Contact(colander.MappingSchema): user = colander.SchemaNode(colander.String()) passwd = colander.SchemaNode(colander.String())

def form(environ, start_response): start_response('200 OK') from webob import Request request = Request(environ)

form = deform.Form(Contact(), buttons=('submit'),) if request.POST : submitted = request.POST.items() try: form.validate(submitted) except deform.ValidationFailure as e: return template.render(form=e.render()) data = {'user': 'admin', 'passwd': '123'} return template.render(form=form.render(data))

if name == 'main': from paste.httpserver import serve

serve(simple_form, host='0.0.0.0', port=8000)

Хранение паролей Moin никогда не хранит пароли пользователей вики в открытом виде, вместо этого использует криптографические хеши паролей, получаемы при помощи библиоткеки passlib. Документация passlib рекомендует 3 схемы хеширования, обеспечивающие хороший уровень безопасности: sha512_crypt, pbkdf2_sha512 и bcrypt (bcrypt требует ещё дополнительные бинарные пакеты, смотрите библиотеку passlib). По умолчанию мы используем sha512_crypt хеши со значениями по умолчанию (это тот же алгоритм, который использется в moin>=1.9.7) В случае если вход в систему занимает слишком много времени или Вы по другой причине хотите заменить генератор хешей, обращайтесь к документации passlib. Moin позволяет Вам настроить параметр CryptContext библиотеки passlib в конфиге вики (вот пример по умолчанию)5

passlib_crypt_context = dict( schemes=["sha512_crypt",], )

Галимзянов А.Ф. Цветков В.К.

RaccoonBoyG commented 7 years ago

Назначение списков ACL для объектов ресурсов Когда по умолчанию политика авторизации Pyramid определяет, обладает ли пользователь определенным разрешением в отношении ресурса, он проверяет ACL, связанный с ресурсом. ACL связан с ресурсом, добавив атрибут acl к ресурсу. Этот атрибут может быть определен в экземпляре ресурса, если вам нужна защита на уровне экземпляра, или он может быть определен в классе ресурса, если вам просто нужна безопасность на уровне типа. Например, ACL может быть присоединен к ресурсу для блога через его класс: from pyramid.security import Allow from pyramid.security import Everyone

class Blog(object): acl = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] Или, если ваши ресурсы постоянны, ACL может быть указан через атрибут acl экземпляра ресурса: from pyramid.security import Allow from pyramid.security import Everyone

class Blog(object): pass

blog = Blog()

blog.acl = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] Независимо от того, присоединяется ли ACL к классу ресурса или экземпляру самого ресурса, эффект остается тем же. Полезно украшать отдельные экземпляры ресурсов списком ACL (в отличие от просто украшения их класса) в таких приложениях, как системы управления контентом, где требуется мелкомасштабный доступ к объектной основе.

Динамические ACL также возможны, если ACL становится вызываемой на ресурсе. Это может позволить ACL динамически создавать правила на основе свойств экземпляра. from pyramid.security import Allow from pyramid.security import Everyone

class Blog(object): def acl(self): return [ (Allow, Everyone, 'view'), (Allow, self.owner, 'edit'), (Allow, 'group:editors', 'edit'), ]

def __init__(self, owner):
    self.owner = owner

Написание acl как свойств не рекомендуется, поскольку AttributeError, встречающийся в fget или fset, будет молча отстранен (это соответствует поведениям getattr и hasattr в Python). Для динамических списков ACL просто используйте callables, как описано выше. Элементы ACL Вот пример ACL: from pyramid.security import Allow from pyramid.security import Everyone

acl = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', 'add'), (Allow, 'group:editors', 'edit'), ] Пример ACL указывает, что pyramid.security.Everyone - специальный определяемый системой главный, указывающий, буквально, каждому - разрешено просматривать блог, а группе: редактору-редактору разрешено добавлять и редактировать блог.

Каждый элемент ACL является ACE или элементом управления доступом. Например, в приведенном выше блоке кода есть три ACE: (Allow, Everyone, 'view'), (Allow, 'group: editors', 'add') и (Allow, 'group: editors', 'edit ').

Первым элементом любого ACE является либо pyramid.security.Allow, либо pyramid.security.Deny, представляющий действие, выполняемое при совпадении ACE. Второй элемент - главный. Третий аргумент - это разрешение или последовательность имен разрешений.

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

Каждый ACE в ACL обрабатывается политикой авторизации в порядке, определяемом ACL. Итак, если у вас есть ACL вроде этого: from pyramid.security import Allow from pyramid.security import Deny from pyramid.security import Everyone

acl = [ (Allow, Everyone, 'view'), (Deny, Everyone, 'view'), ]

По умолчанию политика авторизации разрешает каждому разрешение на просмотр, хотя позже в ACL у вас есть ACE, который отказывает всем в разрешении на просмотр. С другой стороны, если у вас есть ACL, например: from pyramid.security import Everyone from pyramid.security import Allow from pyramid.security import Deny

acl = [ (Deny, Everyone, 'view'), (Allow, Everyone, 'view'), ]

Политика авторизации откажет всем в разрешении на просмотр, хотя позже в ACL есть ACE, который позволяет всем.

Третий аргумент в ACE также может быть последовательностью имен разрешений вместо одного имени разрешения. Поэтому вместо создания нескольких ACE, представляющих несколько разных разрешений для одной группы: группу редакторов, мы можем свернуть ее в один ACE, как показано ниже. from pyramid.security import Allow from pyramid.security import Everyone

acl = [ (Allow, Everyone, 'view'), (Allow, 'group:editors', ('add', 'edit')),


RaccoonBoyG commented 7 years ago

Создание собственной политики авторизации Политика авторизации - это политика, которая разрешает или запрещает доступ после аутентификации пользователя. Большинство приложений Pyramid будут использовать стандартную pyramid.authorization.ACLAuthorizationPolicy.

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

Пирамида поставляется только с единой политикой авторизации по умолчанию, поэтому вам нужно создать свой собственный, если вы хотите использовать другой. Создание и использование вашей собственной политики авторизации - это вопрос создания экземпляра объекта, который реализует следующий интерфейс: class IAuthorizationPolicy(object): """ An object representing a Pyramid authorization policy. """ def permits(self, context, principals, permission): """ Return True if any of the principals is allowed the permission in the current context, else return False """

def principals_allowed_by_permission(self, context, permission):
    """ Return a set of principal identifiers allowed by the
    ``permission`` in ``context``.  This behavior is optional; if you
    choose to not implement it you should define this method as
    something which raises a ``NotImplementedError``.  This method
    will only be called when the
    ``pyramid.security.principals_allowed_by_permission`` API is
    used."""

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

RaccoonBoyG commented 7 years ago

passlib.hash.bcrypt - BCrypt BCrypt был разработан для замены md5_crypt для систем BSD. Он использует модифицированную версию потокового шифрования Blowfish. В настоящее время это хэш пароля по умолчанию для многих систем (в частности, BSD) и не имеет известных слабых мест. Это один из четырех хешей, которые Passlib рекомендует для новых приложений. Этот класс можно использовать напрямую следующим образом:

from passlib.hash import bcrypt

generate new salt, hash password h = bcrypt.hash("password") h '$2a$12$NT0I31Sa7ihGEWpka9ASYrEFkhuTNeBQ2xfZskIiiJeyFXhRgS.Sy'

the same, but with an explicit number of rounds bcrypt.using(rounds=8).hash("password") '$2a$08$8wmNsdCH.M21f.LSBSnYjQrZ9l1EmtBc9uNPGL.9l75YE8D8FlnZC'

verify password bcrypt.verify("password", h) True bcrypt.verify("wrong", h) False

Интерфейс class passlib.hash.bcrypt

Этот класс реализует хэш пароля шифрования BCrypt и следует API PasswordHash. Он поддерживает соль фиксированной длины и переменное количество раундов. Метод using () принимает следующие необязательные ключевые слова: Параметры: Salt (str) - дополнительный salt-string. Если не указано, будет автоматически автогенерирован (это рекомендуется). Если указано, это должно быть 22 символа, взятых из диапазона регулярных выражений [./0-9A-Za-z]. Rounds (int) - Значение по умолчанию - 12, должно быть от 4 до 31 включительно. Это значение логарифмическое, фактическое количество используемых итераций будет 2 ** раунда - увеличение раундов на +1 удвоит количество времени. Ident (str) - Определяет, какая версия алгоритма BCrypt будет использоваться при создании нового хеша. Обычно эта опция не требуется, так как по умолчанию ("2b") обычно является правильным выбором. Если указано, это должно быть одно из следующего: «2» - первая ревизия BCrypt, которая страдает незначительным недостатком безопасности и, как правило, больше не используется. «2a» - некоторые реализации пострадали от редких недостатков безопасности, замененных на 2b. «2y» - формат, специфичный для реализации crypt_blowfish BCrypt, идентичный «2b» во всех, кроме имени. «2b» - последняя версия официального алгоритма BCrypt, текущее значение по умолчанию. Truncate_error (bool) - По умолчанию BCrypt будет молча усекать пароли размером более 72 байт. Установка truncate_error = True вызовет hash () для повышения значения PasswordTruncateError.

Новое в версии 1.7.

Relaxed (bool) - По умолчанию предоставление недопустимого значения для одного из других ключевых слов приведет к значению ValueError. Если relaxed = True, и ошибку можно исправить, вместо нее будет выдан PasslibHashWarning. Исправимые ошибки включают слишком маленькие или слишком большие кружки и слишком длинные salt-строки. Relaxed (bool) - По умолчанию предоставление недопустимого значения для одного из других ключевых слов приведет к значению ValueError. Если relaxed = True, и ошибка может быть исправлена, вместо нее будет выдан PasslibHashWarning. Исправляемые ошибки включают слишком маленькие или слишком большие раунды, а слишком длинные salt-строки. Bcrypt Backends

Этот класс будет использовать первый доступный из пяти возможных серверов:

Bcrypt, если он установлен. Py-bcrypt, если он установлен. Bcryptor, если он установлен. Stdlib crypt.crypt (), если ОС хоста поддерживает BCrypt (в основном, BSD-производные системы). Чисто-питонная реализация BCrypt, встроенная в Passlib. Если никакие бэкенды не доступны, hash () и verify () будут вызывать MissingBackendError, когда они будут вызваны. Вы можете проверить, какой бэкэнд используется, вызвав bcrypt.get_backend ().

Начиная с версии Passlib 1.6.3, однократная проверка выполняется при первом запуске бэкэнд, чтобы определить возможности и ошибки в бэкэнд. Если эта проверка обнаруживает фатальную ошибку, возникает уязвимость PasslibSecurityError. Как правило, это означает, что вам необходимо обновить внешний пакет, используемый в качестве бэкэнда (это будет подробно описано в сообщении об ошибке). ФОРМАТ И АЛГОРИТМ Формат и алгоритм Bcrypt совместим с модульным форматом шифрования и использует ряд идентифицирующих префиксов: $ 2 $, $ 2a $, $ 2x $, $ 2y $ и $ 2b $. Каждый префикс указывает на другую ревизию алгоритма BCrypt; И все, кроме идентификатора $ 2b $, считаются устаревшими. Пример хэша (пароля): $2b$12$GhvMmNVjRW29ulnudl.LbuAnUtN/LRfe1JsBm1Xu6LE3059z5Tr8m Хеши Bcrypt имеют формат $ 2a $ rounds $ saltchecksum, где:

Rounds - это параметр стоимости, закодированный как 2 нулевые десятичные цифры, которые определяют количество итераций, используемых через итерации = 2 ** раунда (раунды - 12 в примере). Salt - это 22-символьная соль, используя символы в диапазоне регулярных выражений [./A-Za-z0-9] (GhvMmNVjRW29ulnudl.Lbu в примере). Контрольная сумма - контрольная сумма из 31 символа, используя те же символы, что и соль (AnUtN / LRfe1JsBm1Xu6LE3059z5Tr8m в примере). Хотя базовый алгоритм BCrypt описан в его проектном документе, реализация OpenBSD считается канонической ссылкой, хотя и несколько отличается от дизайна документа.