Merge branch 'master' into pyup-scheduled-update-12-11-2017
This commit is contained in:
commit
82a8a18bc0
|
@ -1,6 +1,5 @@
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- 3.4.3
|
|
||||||
- 3.5
|
- 3.5
|
||||||
- 3.6
|
- 3.6
|
||||||
- 3.7-dev
|
- 3.7-dev
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
import abc
|
import abc
|
||||||
import asyncio
|
|
||||||
|
|
||||||
# see http://plope.com/pyramid_auth_design_api_postmortem
|
# see http://plope.com/pyramid_auth_design_api_postmortem
|
||||||
|
|
||||||
|
|
||||||
class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
|
class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def identify(self, request):
|
async def identify(self, request):
|
||||||
"""Return the claimed identity of the user associated request or
|
"""Return the claimed identity of the user associated request or
|
||||||
``None`` if no identity can be found associated with the request."""
|
``None`` if no identity can be found associated with the request."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def remember(self, request, response, identity, **kwargs):
|
async def remember(self, request, response, identity, **kwargs):
|
||||||
"""Remember identity.
|
"""Remember identity.
|
||||||
|
|
||||||
Modify response object by filling it's headers with remembered user.
|
Modify response object by filling it's headers with remembered user.
|
||||||
|
@ -25,9 +22,8 @@ class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def forget(self, request, response):
|
async def forget(self, request, response):
|
||||||
""" Modify response which can be used to 'forget' the
|
""" Modify response which can be used to 'forget' the
|
||||||
current identity on subsequent requests."""
|
current identity on subsequent requests."""
|
||||||
pass
|
pass
|
||||||
|
@ -35,9 +31,8 @@ class AbstractIdentityPolicy(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
class AbstractAuthorizationPolicy(metaclass=abc.ABCMeta):
|
class AbstractAuthorizationPolicy(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def permits(self, identity, permission, context=None):
|
async def permits(self, identity, permission, context=None):
|
||||||
"""Check user permissions.
|
"""Check user permissions.
|
||||||
|
|
||||||
Return True if the identity is allowed the permission in the
|
Return True if the identity is allowed the permission in the
|
||||||
|
@ -45,9 +40,8 @@ class AbstractAuthorizationPolicy(metaclass=abc.ABCMeta):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def authorized_userid(self, identity):
|
async def authorized_userid(self, identity):
|
||||||
"""Retrieve authorized user id.
|
"""Retrieve authorized user id.
|
||||||
|
|
||||||
Return the user_id of the user identified by the identity
|
Return the user_id of the user identified by the identity
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import enum
|
import enum
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_security.abc import (AbstractIdentityPolicy,
|
from aiohttp_security.abc import (AbstractIdentityPolicy,
|
||||||
|
@ -9,8 +8,7 @@ IDENTITY_KEY = 'aiohttp_security_identity_policy'
|
||||||
AUTZ_KEY = 'aiohttp_security_autz_policy'
|
AUTZ_KEY = 'aiohttp_security_autz_policy'
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def remember(request, response, identity, **kwargs):
|
||||||
def remember(request, response, identity, **kwargs):
|
|
||||||
"""Remember identity into response.
|
"""Remember identity into response.
|
||||||
|
|
||||||
The action is performed by identity_policy.remember()
|
The action is performed by identity_policy.remember()
|
||||||
|
@ -28,11 +26,10 @@ def remember(request, response, identity, **kwargs):
|
||||||
# output and rendered page we add same message to *reason* and
|
# output and rendered page we add same message to *reason* and
|
||||||
# *text* arguments.
|
# *text* arguments.
|
||||||
raise web.HTTPInternalServerError(reason=text, text=text)
|
raise web.HTTPInternalServerError(reason=text, text=text)
|
||||||
yield from identity_policy.remember(request, response, identity, **kwargs)
|
await identity_policy.remember(request, response, identity, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def forget(request, response):
|
||||||
def forget(request, response):
|
|
||||||
"""Forget previously remembered identity.
|
"""Forget previously remembered identity.
|
||||||
|
|
||||||
Usually it clears cookie or server-side storage to forget user
|
Usually it clears cookie or server-side storage to forget user
|
||||||
|
@ -46,38 +43,35 @@ def forget(request, response):
|
||||||
# output and rendered page we add same message to *reason* and
|
# output and rendered page we add same message to *reason* and
|
||||||
# *text* arguments.
|
# *text* arguments.
|
||||||
raise web.HTTPInternalServerError(reason=text, text=text)
|
raise web.HTTPInternalServerError(reason=text, text=text)
|
||||||
yield from identity_policy.forget(request, response)
|
await identity_policy.forget(request, response)
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def authorized_userid(request):
|
||||||
def authorized_userid(request):
|
|
||||||
identity_policy = request.app.get(IDENTITY_KEY)
|
identity_policy = request.app.get(IDENTITY_KEY)
|
||||||
autz_policy = request.app.get(AUTZ_KEY)
|
autz_policy = request.app.get(AUTZ_KEY)
|
||||||
if identity_policy is None or autz_policy is None:
|
if identity_policy is None or autz_policy is None:
|
||||||
return None
|
return None
|
||||||
identity = yield from identity_policy.identify(request)
|
identity = await identity_policy.identify(request)
|
||||||
if identity is None:
|
if identity is None:
|
||||||
return None # non-registered user has None user_id
|
return None # non-registered user has None user_id
|
||||||
user_id = yield from autz_policy.authorized_userid(identity)
|
user_id = await autz_policy.authorized_userid(identity)
|
||||||
return user_id
|
return user_id
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(request, permission, context=None):
|
||||||
def permits(request, permission, context=None):
|
|
||||||
assert isinstance(permission, (str, enum.Enum)), permission
|
assert isinstance(permission, (str, enum.Enum)), permission
|
||||||
assert permission
|
assert permission
|
||||||
identity_policy = request.app.get(IDENTITY_KEY)
|
identity_policy = request.app.get(IDENTITY_KEY)
|
||||||
autz_policy = request.app.get(AUTZ_KEY)
|
autz_policy = request.app.get(AUTZ_KEY)
|
||||||
if identity_policy is None or autz_policy is None:
|
if identity_policy is None or autz_policy is None:
|
||||||
return True
|
return True
|
||||||
identity = yield from identity_policy.identify(request)
|
identity = await identity_policy.identify(request)
|
||||||
# non-registered user still may has some permissions
|
# non-registered user still may has some permissions
|
||||||
access = yield from autz_policy.permits(identity, permission, context)
|
access = await autz_policy.permits(identity, permission, context)
|
||||||
return access
|
return access
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def is_anonymous(request):
|
||||||
def is_anonymous(request):
|
|
||||||
"""Check if user is anonymous.
|
"""Check if user is anonymous.
|
||||||
|
|
||||||
User is considered anonymous if there is not identity
|
User is considered anonymous if there is not identity
|
||||||
|
@ -86,7 +80,7 @@ def is_anonymous(request):
|
||||||
identity_policy = request.app.get(IDENTITY_KEY)
|
identity_policy = request.app.get(IDENTITY_KEY)
|
||||||
if identity_policy is None:
|
if identity_policy is None:
|
||||||
return True
|
return True
|
||||||
identity = yield from identity_policy.identify(request)
|
identity = await identity_policy.identify(request)
|
||||||
if identity is None:
|
if identity is None:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
@ -98,9 +92,8 @@ def login_required(fn):
|
||||||
User is considered authorized if authorized_userid
|
User is considered authorized if authorized_userid
|
||||||
returns some value.
|
returns some value.
|
||||||
"""
|
"""
|
||||||
@asyncio.coroutine
|
|
||||||
@wraps(fn)
|
@wraps(fn)
|
||||||
def wrapped(*args, **kwargs):
|
async def wrapped(*args, **kwargs):
|
||||||
request = args[-1]
|
request = args[-1]
|
||||||
if not isinstance(request, web.BaseRequest):
|
if not isinstance(request, web.BaseRequest):
|
||||||
msg = ("Incorrect decorator usage. "
|
msg = ("Incorrect decorator usage. "
|
||||||
|
@ -108,11 +101,11 @@ def login_required(fn):
|
||||||
"or `def handler(self, request)`.")
|
"or `def handler(self, request)`.")
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
userid = yield from authorized_userid(request)
|
userid = await authorized_userid(request)
|
||||||
if userid is None:
|
if userid is None:
|
||||||
raise web.HTTPUnauthorized
|
raise web.HTTPUnauthorized
|
||||||
|
|
||||||
ret = yield from fn(*args, **kwargs)
|
ret = await fn(*args, **kwargs)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return wrapped
|
return wrapped
|
||||||
|
@ -130,9 +123,8 @@ def has_permission(
|
||||||
raises HTTPForbidden.
|
raises HTTPForbidden.
|
||||||
"""
|
"""
|
||||||
def wrapper(fn):
|
def wrapper(fn):
|
||||||
@asyncio.coroutine
|
|
||||||
@wraps(fn)
|
@wraps(fn)
|
||||||
def wrapped(*args, **kwargs):
|
async def wrapped(*args, **kwargs):
|
||||||
request = args[-1]
|
request = args[-1]
|
||||||
if not isinstance(request, web.BaseRequest):
|
if not isinstance(request, web.BaseRequest):
|
||||||
msg = ("Incorrect decorator usage. "
|
msg = ("Incorrect decorator usage. "
|
||||||
|
@ -140,14 +132,14 @@ def has_permission(
|
||||||
"or `def handler(self, request)`.")
|
"or `def handler(self, request)`.")
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
userid = yield from authorized_userid(request)
|
userid = await authorized_userid(request)
|
||||||
if userid is None:
|
if userid is None:
|
||||||
raise web.HTTPUnauthorized
|
raise web.HTTPUnauthorized
|
||||||
|
|
||||||
allowed = yield from permits(request, permission, context)
|
allowed = await permits(request, permission, context)
|
||||||
if not allowed:
|
if not allowed:
|
||||||
raise web.HTTPForbidden
|
raise web.HTTPForbidden
|
||||||
ret = yield from fn(*args, **kwargs)
|
ret = await fn(*args, **kwargs)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
return wrapped
|
return wrapped
|
||||||
|
|
|
@ -5,8 +5,6 @@ more handy.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from .abc import AbstractIdentityPolicy
|
from .abc import AbstractIdentityPolicy
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,19 +17,16 @@ class CookiesIdentityPolicy(AbstractIdentityPolicy):
|
||||||
self._cookie_name = 'AIOHTTP_SECURITY'
|
self._cookie_name = 'AIOHTTP_SECURITY'
|
||||||
self._max_age = 30 * 24 * 3600
|
self._max_age = 30 * 24 * 3600
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def identify(self, request):
|
||||||
def identify(self, request):
|
|
||||||
identity = request.cookies.get(self._cookie_name)
|
identity = request.cookies.get(self._cookie_name)
|
||||||
return identity
|
return identity
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def remember(self, request, response, identity, max_age=sentinel,
|
||||||
def remember(self, request, response, identity, max_age=sentinel,
|
**kwargs):
|
||||||
**kwargs):
|
|
||||||
if max_age is sentinel:
|
if max_age is sentinel:
|
||||||
max_age = self._max_age
|
max_age = self._max_age
|
||||||
response.set_cookie(self._cookie_name, identity,
|
response.set_cookie(self._cookie_name, identity,
|
||||||
max_age=max_age, **kwargs)
|
max_age=max_age, **kwargs)
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def forget(self, request, response):
|
||||||
def forget(self, request, response):
|
|
||||||
response.del_cookie(self._cookie_name)
|
response.del_cookie(self._cookie_name)
|
||||||
|
|
|
@ -4,8 +4,6 @@ aiohttp_session.setup() should be called on application initialization
|
||||||
to configure aiohttp_session properly.
|
to configure aiohttp_session properly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from aiohttp_session import get_session
|
from aiohttp_session import get_session
|
||||||
HAS_AIOHTTP_SESSION = True
|
HAS_AIOHTTP_SESSION = True
|
||||||
|
@ -24,17 +22,14 @@ class SessionIdentityPolicy(AbstractIdentityPolicy):
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
'SessionIdentityPolicy requires `aiohttp_session`')
|
'SessionIdentityPolicy requires `aiohttp_session`')
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def identify(self, request):
|
||||||
def identify(self, request):
|
session = await get_session(request)
|
||||||
session = yield from get_session(request)
|
|
||||||
return session.get(self._session_key)
|
return session.get(self._session_key)
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def remember(self, request, response, identity, **kwargs):
|
||||||
def remember(self, request, response, identity, **kwargs):
|
session = await get_session(request)
|
||||||
session = yield from get_session(request)
|
|
||||||
session[self._session_key] = identity
|
session[self._session_key] = identity
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def forget(self, request, response):
|
||||||
def forget(self, request, response):
|
session = await get_session(request)
|
||||||
session = yield from get_session(request)
|
|
||||||
session.pop(self._session_key, None)
|
session.pop(self._session_key, None)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import asyncio
|
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from aiohttp_security.abc import AbstractAuthorizationPolicy
|
from aiohttp_security.abc import AbstractAuthorizationPolicy
|
||||||
|
@ -12,29 +10,27 @@ class DBAuthorizationPolicy(AbstractAuthorizationPolicy):
|
||||||
def __init__(self, dbengine):
|
def __init__(self, dbengine):
|
||||||
self.dbengine = dbengine
|
self.dbengine = dbengine
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def authorized_userid(self, identity):
|
def authorized_userid(self, identity):
|
||||||
with (yield from self.dbengine) as conn:
|
async with self.dbengine as conn:
|
||||||
where = sa.and_(db.users.c.login == identity,
|
where = sa.and_(db.users.c.login == identity,
|
||||||
sa.not_(db.users.c.disabled))
|
sa.not_(db.users.c.disabled))
|
||||||
query = db.users.count().where(where)
|
query = db.users.count().where(where)
|
||||||
ret = yield from conn.scalar(query)
|
ret = await conn.scalar(query)
|
||||||
if ret:
|
if ret:
|
||||||
return identity
|
return identity
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(self, identity, permission, context=None):
|
||||||
def permits(self, identity, permission, context=None):
|
|
||||||
if identity is None:
|
if identity is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
with (yield from self.dbengine) as conn:
|
async with self.dbengine as conn:
|
||||||
where = sa.and_(db.users.c.login == identity,
|
where = sa.and_(db.users.c.login == identity,
|
||||||
sa.not_(db.users.c.disabled))
|
sa.not_(db.users.c.disabled))
|
||||||
query = db.users.select().where(where)
|
query = db.users.select().where(where)
|
||||||
ret = yield from conn.execute(query)
|
ret = await conn.execute(query)
|
||||||
user = yield from ret.fetchone()
|
user = await ret.fetchone()
|
||||||
if user is not None:
|
if user is not None:
|
||||||
user_id = user[0]
|
user_id = user[0]
|
||||||
is_superuser = user[3]
|
is_superuser = user[3]
|
||||||
|
@ -43,8 +39,8 @@ class DBAuthorizationPolicy(AbstractAuthorizationPolicy):
|
||||||
|
|
||||||
where = db.permissions.c.user_id == user_id
|
where = db.permissions.c.user_id == user_id
|
||||||
query = db.permissions.select().where(where)
|
query = db.permissions.select().where(where)
|
||||||
ret = yield from conn.execute(query)
|
ret = await conn.execute(query)
|
||||||
result = yield from ret.fetchall()
|
result = await ret.fetchall()
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
for record in result:
|
for record in result:
|
||||||
if record.perm_name == permission:
|
if record.perm_name == permission:
|
||||||
|
@ -53,14 +49,13 @@ class DBAuthorizationPolicy(AbstractAuthorizationPolicy):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check_credentials(db_engine, username, password):
|
||||||
def check_credentials(db_engine, username, password):
|
async with db_engine as conn:
|
||||||
with (yield from db_engine) as conn:
|
|
||||||
where = sa.and_(db.users.c.login == username,
|
where = sa.and_(db.users.c.login == username,
|
||||||
sa.not_(db.users.c.disabled))
|
sa.not_(db.users.c.disabled))
|
||||||
query = db.users.select().where(where)
|
query = db.users.select().where(where)
|
||||||
ret = yield from conn.execute(query)
|
ret = await conn.execute(query)
|
||||||
user = yield from ret.fetchone()
|
user = await ret.fetchone()
|
||||||
if user is not None:
|
if user is not None:
|
||||||
hash = user[2]
|
hash = user[2]
|
||||||
return sha256_crypt.verify(password, hash)
|
return sha256_crypt.verify(password, hash)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
@ -10,14 +9,13 @@ from .db_auth import check_credentials
|
||||||
|
|
||||||
def require(permission):
|
def require(permission):
|
||||||
def wrapper(f):
|
def wrapper(f):
|
||||||
@asyncio.coroutine
|
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapped(self, request):
|
async def wrapped(self, request):
|
||||||
has_perm = yield from permits(request, permission)
|
has_perm = await permits(request, permission)
|
||||||
if not has_perm:
|
if not has_perm:
|
||||||
message = 'User has no permission {}'.format(permission)
|
message = 'User has no permission {}'.format(permission)
|
||||||
raise web.HTTPForbidden(body=message.encode())
|
raise web.HTTPForbidden(body=message.encode())
|
||||||
return (yield from f(self, request))
|
return await f(self, request)
|
||||||
return wrapped
|
return wrapped
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
@ -40,9 +38,8 @@ class Web(object):
|
||||||
</body>
|
</body>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def index(self, request):
|
||||||
def index(self, request):
|
username = await authorized_userid(request)
|
||||||
username = yield from authorized_userid(request)
|
|
||||||
if username:
|
if username:
|
||||||
template = self.index_template.format(
|
template = self.index_template.format(
|
||||||
message='Hello, {username}!'.format(username=username))
|
message='Hello, {username}!'.format(username=username))
|
||||||
|
@ -51,37 +48,33 @@ class Web(object):
|
||||||
response = web.Response(body=template.encode())
|
response = web.Response(body=template.encode())
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(self, request):
|
||||||
def login(self, request):
|
|
||||||
response = web.HTTPFound('/')
|
response = web.HTTPFound('/')
|
||||||
form = yield from request.post()
|
form = await request.post()
|
||||||
login = form.get('login')
|
login = form.get('login')
|
||||||
password = form.get('password')
|
password = form.get('password')
|
||||||
db_engine = request.app.db_engine
|
db_engine = request.app.db_engine
|
||||||
if (yield from check_credentials(db_engine, login, password)):
|
if await check_credentials(db_engine, login, password):
|
||||||
yield from remember(request, response, login)
|
await remember(request, response, login)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
return web.HTTPUnauthorized(
|
return web.HTTPUnauthorized(
|
||||||
body=b'Invalid username/password combination')
|
body=b'Invalid username/password combination')
|
||||||
|
|
||||||
@require('public')
|
@require('public')
|
||||||
@asyncio.coroutine
|
async def logout(self, request):
|
||||||
def logout(self, request):
|
|
||||||
response = web.Response(body=b'You have been logged out')
|
response = web.Response(body=b'You have been logged out')
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@require('public')
|
@require('public')
|
||||||
@asyncio.coroutine
|
async def internal_page(self, request):
|
||||||
def internal_page(self, request):
|
|
||||||
response = web.Response(
|
response = web.Response(
|
||||||
body=b'This page is visible for all registered users')
|
body=b'This page is visible for all registered users')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@require('protected')
|
@require('protected')
|
||||||
@asyncio.coroutine
|
async def protected_page(self, request):
|
||||||
def protected_page(self, request):
|
|
||||||
response = web.Response(body=b'You are on protected page')
|
response = web.Response(body=b'You are on protected page')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,9 @@ from demo.db_auth import DBAuthorizationPolicy
|
||||||
from demo.handlers import Web
|
from demo.handlers import Web
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def init(loop):
|
def init(loop):
|
||||||
redis_pool = yield from create_pool(('localhost', 6379))
|
redis_pool = await create_pool(('localhost', 6379))
|
||||||
db_engine = yield from create_engine(user='aiohttp_security',
|
db_engine = await create_engine(user='aiohttp_security',
|
||||||
password='aiohttp_security',
|
password='aiohttp_security',
|
||||||
database='aiohttp_security',
|
database='aiohttp_security',
|
||||||
host='127.0.0.1')
|
host='127.0.0.1')
|
||||||
|
@ -31,21 +30,20 @@ def init(loop):
|
||||||
web_handlers.configure(app)
|
web_handlers.configure(app)
|
||||||
|
|
||||||
handler = app.make_handler()
|
handler = app.make_handler()
|
||||||
srv = yield from loop.create_server(handler, '127.0.0.1', 8080)
|
srv = await loop.create_server(handler, '127.0.0.1', 8080)
|
||||||
print('Server started at http://127.0.0.1:8080')
|
print('Server started at http://127.0.0.1:8080')
|
||||||
return srv, app, handler
|
return srv, app, handler
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def finalize(srv, app, handler):
|
||||||
def finalize(srv, app, handler):
|
|
||||||
sock = srv.sockets[0]
|
sock = srv.sockets[0]
|
||||||
app.loop.remove_reader(sock.fileno())
|
app.loop.remove_reader(sock.fileno())
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
yield from handler.finish_connections(1.0)
|
await handler.finish_connections(1.0)
|
||||||
srv.close()
|
srv.close()
|
||||||
yield from srv.wait_closed()
|
await srv.wait_closed()
|
||||||
yield from app.finish()
|
await app.finish()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import functools
|
import functools
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
|
@ -11,14 +10,13 @@ from .authz import check_credentials
|
||||||
|
|
||||||
def require(permission):
|
def require(permission):
|
||||||
def wrapper(f):
|
def wrapper(f):
|
||||||
@asyncio.coroutine
|
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapped(request):
|
async def wrapped(request):
|
||||||
has_perm = yield from permits(request, permission)
|
has_perm = await permits(request, permission)
|
||||||
if not has_perm:
|
if not has_perm:
|
||||||
message = 'User has no permission {}'.format(permission)
|
message = 'User has no permission {}'.format(permission)
|
||||||
raise web.HTTPForbidden(body=message.encode())
|
raise web.HTTPForbidden(body=message.encode())
|
||||||
return (yield from f(request))
|
return await f(request)
|
||||||
return wrapped
|
return wrapped
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
|
@ -10,16 +10,14 @@ Simple example::
|
||||||
import asyncio
|
import asyncio
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def root_handler(request):
|
||||||
def root_handler(request):
|
|
||||||
text = "Alive and kicking!"
|
text = "Alive and kicking!"
|
||||||
return web.Response(body=text.encode('utf-8'))
|
return web.Response(body=text.encode('utf-8'))
|
||||||
|
|
||||||
# option 2: auth at a higher level?
|
# option 2: auth at a higher level?
|
||||||
# set user_id and allowed in the wsgi handler
|
# set user_id and allowed in the wsgi handler
|
||||||
@protect('view_user')
|
@protect('view_user')
|
||||||
@asyncio.coroutine
|
async def user_handler(request):
|
||||||
def user_handler(request):
|
|
||||||
name = request.match_info.get('name', "Anonymous")
|
name = request.match_info.get('name', "Anonymous")
|
||||||
text = "Hello, " + name
|
text = "Hello, " + name
|
||||||
return web.Response(body=text.encode('utf-8'))
|
return web.Response(body=text.encode('utf-8'))
|
||||||
|
@ -27,14 +25,12 @@ Simple example::
|
||||||
|
|
||||||
# option 3: super low
|
# option 3: super low
|
||||||
# wsgi doesn't do anything
|
# wsgi doesn't do anything
|
||||||
@asyncio.coroutine
|
async def user_update_handler(request):
|
||||||
def user_update_handler(request):
|
|
||||||
# identity, asked_permission
|
# identity, asked_permission
|
||||||
user_id = yield from identity_policy.identify(request)
|
user_id = await identity_policy.identify(request)
|
||||||
identity = yield from auth_policy.authorized_user_id(user_id)
|
identity = await auth_policy.authorized_user_id(user_id)
|
||||||
allowed = yield from request.auth_policy.permits(
|
allowed = await request.auth_policy.permits(identity,
|
||||||
identity, asked_permission
|
asked_permission)
|
||||||
)
|
|
||||||
if not allowed:
|
if not allowed:
|
||||||
# how is this pluggable as well?
|
# how is this pluggable as well?
|
||||||
# ? return NotAllowedStream()
|
# ? return NotAllowedStream()
|
||||||
|
@ -42,8 +38,7 @@ Simple example::
|
||||||
|
|
||||||
update_user()
|
update_user()
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def init(loop):
|
||||||
def init(loop):
|
|
||||||
# set up identity and auth
|
# set up identity and auth
|
||||||
auth_policy = DictionaryAuthorizationPolicy({'me': ('view_user',),
|
auth_policy = DictionaryAuthorizationPolicy({'me': ('view_user',),
|
||||||
'you': ('view_user',
|
'you': ('view_user',
|
||||||
|
@ -60,7 +55,7 @@ Simple example::
|
||||||
app.router.add_route('GET', '/{user}/edit', user_update_handler)
|
app.router.add_route('GET', '/{user}/edit', user_update_handler)
|
||||||
|
|
||||||
# get it started
|
# get it started
|
||||||
srv = yield from loop.create_server(app.make_handler(),
|
srv = await loop.create_server(app.make_handler(),
|
||||||
'127.0.0.1', 8080)
|
'127.0.0.1', 8080)
|
||||||
print("Server started at http://127.0.0.1:8080")
|
print("Server started at http://127.0.0.1:8080")
|
||||||
return srv
|
return srv
|
||||||
|
|
|
@ -67,13 +67,12 @@ In our example we will lookup database by user login and if present return
|
||||||
this identity::
|
this identity::
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def authorized_userid(self, identity):
|
||||||
def authorized_userid(self, identity):
|
async with self.dbengine as conn:
|
||||||
with (yield from self.dbengine) as conn:
|
|
||||||
where = sa.and_(db.users.c.login == identity,
|
where = sa.and_(db.users.c.login == identity,
|
||||||
sa.not_(db.users.c.disabled))
|
sa.not_(db.users.c.disabled))
|
||||||
query = db.users.count().where(where)
|
query = db.users.count().where(where)
|
||||||
ret = yield from conn.scalar(query)
|
ret = await conn.scalar(query)
|
||||||
if ret:
|
if ret:
|
||||||
return identity
|
return identity
|
||||||
else:
|
else:
|
||||||
|
@ -84,17 +83,16 @@ For permission check we will fetch the user first, check if he is superuser
|
||||||
(all permissions are allowed), otherwise check if permission is explicitly set
|
(all permissions are allowed), otherwise check if permission is explicitly set
|
||||||
for that user::
|
for that user::
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(self, identity, permission, context=None):
|
||||||
def permits(self, identity, permission, context=None):
|
|
||||||
if identity is None:
|
if identity is None:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
with (yield from self.dbengine) as conn:
|
async with self.dbengine as conn:
|
||||||
where = sa.and_(db.users.c.login == identity,
|
where = sa.and_(db.users.c.login == identity,
|
||||||
sa.not_(db.users.c.disabled))
|
sa.not_(db.users.c.disabled))
|
||||||
query = db.users.select().where(where)
|
query = db.users.select().where(where)
|
||||||
ret = yield from conn.execute(query)
|
ret = await conn.execute(query)
|
||||||
user = yield from ret.fetchone()
|
user = await ret.fetchone()
|
||||||
if user is not None:
|
if user is not None:
|
||||||
user_id = user[0]
|
user_id = user[0]
|
||||||
is_superuser = user[4]
|
is_superuser = user[4]
|
||||||
|
@ -103,8 +101,8 @@ for that user::
|
||||||
|
|
||||||
where = db.permissions.c.user_id == user_id
|
where = db.permissions.c.user_id == user_id
|
||||||
query = db.permissions.select().where(where)
|
query = db.permissions.select().where(where)
|
||||||
ret = yield from conn.execute(query)
|
ret = await conn.execute(query)
|
||||||
result = yield from ret.fetchall()
|
result = await ret.fetchall()
|
||||||
if ret is not None:
|
if ret is not None:
|
||||||
for record in result:
|
for record in result:
|
||||||
if record.perm_name == permission:
|
if record.perm_name == permission:
|
||||||
|
@ -127,13 +125,12 @@ Once we have all the code in place we can install it for our application::
|
||||||
from .db_auth import DBAuthorizationPolicy
|
from .db_auth import DBAuthorizationPolicy
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def init(loop):
|
||||||
def init(loop):
|
redis_pool = await create_pool(('localhost', 6379))
|
||||||
redis_pool = yield from create_pool(('localhost', 6379))
|
dbengine = await create_engine(user='aiohttp_security',
|
||||||
dbengine = yield from create_engine(user='aiohttp_security',
|
password='aiohttp_security',
|
||||||
password='aiohttp_security',
|
database='aiohttp_security',
|
||||||
database='aiohttp_security',
|
host='127.0.0.1')
|
||||||
host='127.0.0.1')
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
setup_session(app, RedisStorage(redis_pool))
|
setup_session(app, RedisStorage(redis_pool))
|
||||||
setup_security(app,
|
setup_security(app,
|
||||||
|
@ -148,14 +145,13 @@ help to do that::
|
||||||
|
|
||||||
def require(permission):
|
def require(permission):
|
||||||
def wrapper(f):
|
def wrapper(f):
|
||||||
@asyncio.coroutine
|
|
||||||
@functools.wraps(f)
|
@functools.wraps(f)
|
||||||
def wrapped(self, request):
|
async def wrapped(self, request):
|
||||||
has_perm = yield from permits(request, permission)
|
has_perm = await permits(request, permission)
|
||||||
if not has_perm:
|
if not has_perm:
|
||||||
message = 'User has no permission {}'.format(permission)
|
message = 'User has no permission {}'.format(permission)
|
||||||
raise web.HTTPForbidden(body=message.encode())
|
raise web.HTTPForbidden(body=message.encode())
|
||||||
return (yield from f(self, request))
|
return await f(self, request)
|
||||||
return wrapped
|
return wrapped
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
@ -164,8 +160,7 @@ For each view you need to protect just apply the decorator on it::
|
||||||
|
|
||||||
class Web:
|
class Web:
|
||||||
@require('protected')
|
@require('protected')
|
||||||
@asyncio.coroutine
|
async def protected_page(self, request):
|
||||||
def protected_page(self, request):
|
|
||||||
response = web.Response(body=b'You are on protected page')
|
response = web.Response(body=b'You are on protected page')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -187,14 +182,13 @@ function may do what you trying to accomplish::
|
||||||
|
|
||||||
from passlib.hash import sha256_crypt
|
from passlib.hash import sha256_crypt
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check_credentials(db_engine, username, password):
|
||||||
def check_credentials(db_engine, username, password):
|
async with db_engine as conn:
|
||||||
with (yield from db_engine) as conn:
|
|
||||||
where = sa.and_(db.users.c.login == username,
|
where = sa.and_(db.users.c.login == username,
|
||||||
sa.not_(db.users.c.disabled))
|
sa.not_(db.users.c.disabled))
|
||||||
query = db.users.select().where(where)
|
query = db.users.select().where(where)
|
||||||
ret = yield from conn.execute(query)
|
ret = await conn.execute(query)
|
||||||
user = yield from ret.fetchone()
|
user = await ret.fetchone()
|
||||||
if user is not None:
|
if user is not None:
|
||||||
hash = user[2]
|
hash = user[2]
|
||||||
return sha256_crypt.verify(password, hash)
|
return sha256_crypt.verify(password, hash)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_security import (remember, forget,
|
from aiohttp_security import (remember, forget,
|
||||||
AbstractAuthorizationPolicy)
|
AbstractAuthorizationPolicy)
|
||||||
|
@ -10,47 +8,39 @@ from aiohttp_security.api import IDENTITY_KEY
|
||||||
|
|
||||||
class Autz(AbstractAuthorizationPolicy):
|
class Autz(AbstractAuthorizationPolicy):
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(self, identity, permission, context=None):
|
||||||
def permits(self, identity, permission, context=None):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def authorized_userid(self, identity):
|
||||||
def authorized_userid(self, identity):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_remember(loop, test_client):
|
||||||
def test_remember(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def handler(request):
|
||||||
def handler(request):
|
|
||||||
response = web.Response()
|
response = web.Response()
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
_setup(app, CookiesIdentityPolicy(), Autz())
|
_setup(app, CookiesIdentityPolicy(), Autz())
|
||||||
app.router.add_route('GET', '/', handler)
|
app.router.add_route('GET', '/', handler)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
assert 'Andrew' == resp.cookies['AIOHTTP_SECURITY'].value
|
assert 'Andrew' == resp.cookies['AIOHTTP_SECURITY'].value
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_identify(loop, test_client):
|
||||||
def test_identify(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def create(request):
|
||||||
def create(request):
|
|
||||||
response = web.Response()
|
response = web.Response()
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
|
||||||
policy = request.app[IDENTITY_KEY]
|
policy = request.app[IDENTITY_KEY]
|
||||||
user_id = yield from policy.identify(request)
|
user_id = await policy.identify(request)
|
||||||
assert 'Andrew' == user_id
|
assert 'Andrew' == user_id
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
|
@ -58,32 +48,27 @@ def test_identify(loop, test_client):
|
||||||
_setup(app, CookiesIdentityPolicy(), Autz())
|
_setup(app, CookiesIdentityPolicy(), Autz())
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
app.router.add_route('POST', '/', create)
|
app.router.add_route('POST', '/', create)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.post('/')
|
resp = await client.post('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
await resp.release()
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_forget(loop, test_client):
|
||||||
def test_forget(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def index(request):
|
||||||
def index(request):
|
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def logout(request):
|
||||||
def logout(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
|
@ -91,18 +76,17 @@ def test_forget(loop, test_client):
|
||||||
app.router.add_route('GET', '/', index)
|
app.router.add_route('GET', '/', index)
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
app.router.add_route('POST', '/logout', logout)
|
app.router.add_route('POST', '/logout', logout)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.post('/login')
|
resp = await client.post('/login')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
assert str(resp.url).endswith('/')
|
assert str(resp.url).endswith('/')
|
||||||
cookies = client.session.cookie_jar.filter_cookies(
|
cookies = client.session.cookie_jar.filter_cookies(
|
||||||
client.make_url('/'))
|
client.make_url('/'))
|
||||||
assert 'Andrew' == cookies['AIOHTTP_SECURITY'].value
|
assert 'Andrew' == cookies['AIOHTTP_SECURITY'].value
|
||||||
yield from resp.release()
|
|
||||||
resp = yield from client.post('/logout')
|
resp = await client.post('/logout')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
assert str(resp.url).endswith('/')
|
assert str(resp.url).endswith('/')
|
||||||
cookies = client.session.cookie_jar.filter_cookies(
|
cookies = client.session.cookie_jar.filter_cookies(
|
||||||
client.make_url('/'))
|
client.make_url('/'))
|
||||||
assert 'AIOHTTP_SECURITY' not in cookies
|
assert 'AIOHTTP_SECURITY' not in cookies
|
||||||
yield from resp.release()
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
@ -11,33 +10,28 @@ from aiohttp_security.cookies_identity import CookiesIdentityPolicy
|
||||||
|
|
||||||
class Autz(AbstractAuthorizationPolicy):
|
class Autz(AbstractAuthorizationPolicy):
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(self, identity, permission, context=None):
|
||||||
def permits(self, identity, permission, context=None):
|
|
||||||
if identity == 'UserID':
|
if identity == 'UserID':
|
||||||
return permission in {'read', 'write'}
|
return permission in {'read', 'write'}
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def authorized_userid(self, identity):
|
||||||
def authorized_userid(self, identity):
|
|
||||||
if identity == 'UserID':
|
if identity == 'UserID':
|
||||||
return 'Andrew'
|
return 'Andrew'
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_authorized_userid(loop, test_client):
|
||||||
def test_authorized_userid(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'UserID')
|
await remember(request, response, 'UserID')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
userid = await authorized_userid(request)
|
||||||
userid = yield from authorized_userid(request)
|
|
||||||
assert 'Andrew' == userid
|
assert 'Andrew' == userid
|
||||||
return web.Response(text=userid)
|
return web.Response(text=userid)
|
||||||
|
|
||||||
|
@ -45,36 +39,31 @@ def test_authorized_userid(loop, test_client):
|
||||||
_setup(app, CookiesIdentityPolicy(), Autz())
|
_setup(app, CookiesIdentityPolicy(), Autz())
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
|
|
||||||
resp = yield from client.post('/login')
|
resp = await client.post('/login')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
txt = yield from resp.text()
|
txt = await resp.text()
|
||||||
assert 'Andrew' == txt
|
assert 'Andrew' == txt
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_authorized_userid_not_authorized(loop, test_client):
|
||||||
def test_authorized_userid_not_authorized(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
userid = await authorized_userid(request)
|
||||||
userid = yield from authorized_userid(request)
|
|
||||||
assert userid is None
|
assert userid is None
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
_setup(app, CookiesIdentityPolicy(), Autz())
|
_setup(app, CookiesIdentityPolicy(), Autz())
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
|
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_permits_enum_permission(loop, test_client):
|
||||||
def test_permits_enum_permission(loop, test_client):
|
|
||||||
class Permission(enum.Enum):
|
class Permission(enum.Enum):
|
||||||
READ = '101'
|
READ = '101'
|
||||||
WRITE = '102'
|
WRITE = '102'
|
||||||
|
@ -82,33 +71,29 @@ def test_permits_enum_permission(loop, test_client):
|
||||||
|
|
||||||
class Autz(AbstractAuthorizationPolicy):
|
class Autz(AbstractAuthorizationPolicy):
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(self, identity, permission, context=None):
|
||||||
def permits(self, identity, permission, context=None):
|
|
||||||
if identity == 'UserID':
|
if identity == 'UserID':
|
||||||
return permission in {Permission.READ, Permission.WRITE}
|
return permission in {Permission.READ, Permission.WRITE}
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def authorized_userid(self, identity):
|
||||||
def authorized_userid(self, identity):
|
|
||||||
if identity == 'UserID':
|
if identity == 'UserID':
|
||||||
return 'Andrew'
|
return 'Andrew'
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'UserID')
|
await remember(request, response, 'UserID')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
ret = await permits(request, Permission.READ)
|
||||||
ret = yield from permits(request, Permission.READ)
|
|
||||||
assert ret
|
assert ret
|
||||||
ret = yield from permits(request, Permission.WRITE)
|
ret = await permits(request, Permission.WRITE)
|
||||||
assert ret
|
assert ret
|
||||||
ret = yield from permits(request, Permission.UNKNOWN)
|
ret = await permits(request, Permission.UNKNOWN)
|
||||||
assert not ret
|
assert not ret
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
|
@ -116,54 +101,46 @@ def test_permits_enum_permission(loop, test_client):
|
||||||
_setup(app, CookiesIdentityPolicy(), Autz())
|
_setup(app, CookiesIdentityPolicy(), Autz())
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.post('/login')
|
resp = await client.post('/login')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_permits_unauthorized(loop, test_client):
|
||||||
def test_permits_unauthorized(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
ret = await permits(request, 'read')
|
||||||
ret = yield from permits(request, 'read')
|
|
||||||
assert not ret
|
assert not ret
|
||||||
ret = yield from permits(request, 'write')
|
ret = await permits(request, 'write')
|
||||||
assert not ret
|
assert not ret
|
||||||
ret = yield from permits(request, 'unknown')
|
ret = await permits(request, 'unknown')
|
||||||
assert not ret
|
assert not ret
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
_setup(app, CookiesIdentityPolicy(), Autz())
|
_setup(app, CookiesIdentityPolicy(), Autz())
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_is_anonymous(loop, test_client):
|
||||||
def test_is_anonymous(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def index(request):
|
||||||
def index(request):
|
is_anon = await is_anonymous(request)
|
||||||
is_anon = yield from is_anonymous(request)
|
|
||||||
if is_anon:
|
if is_anon:
|
||||||
return web.HTTPUnauthorized()
|
return web.HTTPUnauthorized()
|
||||||
return web.HTTPOk()
|
return web.HTTPOk()
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'UserID')
|
await remember(request, response, 'UserID')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def logout(request):
|
||||||
def logout(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
|
@ -171,36 +148,32 @@ def test_is_anonymous(loop, test_client):
|
||||||
app.router.add_route('GET', '/', index)
|
app.router.add_route('GET', '/', index)
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
app.router.add_route('POST', '/logout', logout)
|
app.router.add_route('POST', '/logout', logout)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
|
|
||||||
yield from client.post('/login')
|
await client.post('/login')
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert web.HTTPOk.status_code == resp.status
|
assert web.HTTPOk.status_code == resp.status
|
||||||
|
|
||||||
yield from client.post('/logout')
|
await client.post('/logout')
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_login_required(loop, test_client):
|
||||||
def test_login_required(loop, test_client):
|
|
||||||
@login_required
|
@login_required
|
||||||
@asyncio.coroutine
|
async def index(request):
|
||||||
def index(request):
|
|
||||||
return web.HTTPOk()
|
return web.HTTPOk()
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'UserID')
|
await remember(request, response, 'UserID')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def logout(request):
|
||||||
def logout(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
|
@ -208,47 +181,41 @@ def test_login_required(loop, test_client):
|
||||||
app.router.add_route('GET', '/', index)
|
app.router.add_route('GET', '/', index)
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
app.router.add_route('POST', '/logout', logout)
|
app.router.add_route('POST', '/logout', logout)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
|
|
||||||
yield from client.post('/login')
|
await client.post('/login')
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert web.HTTPOk.status_code == resp.status
|
assert web.HTTPOk.status_code == resp.status
|
||||||
|
|
||||||
yield from client.post('/logout')
|
await client.post('/logout')
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_has_permission(loop, test_client):
|
||||||
def test_has_permission(loop, test_client):
|
|
||||||
|
|
||||||
@has_permission('read')
|
@has_permission('read')
|
||||||
@asyncio.coroutine
|
async def index_read(request):
|
||||||
def index_read(request):
|
|
||||||
return web.HTTPOk()
|
return web.HTTPOk()
|
||||||
|
|
||||||
@has_permission('write')
|
@has_permission('write')
|
||||||
@asyncio.coroutine
|
async def index_write(request):
|
||||||
def index_write(request):
|
|
||||||
return web.HTTPOk()
|
return web.HTTPOk()
|
||||||
|
|
||||||
@has_permission('forbid')
|
@has_permission('forbid')
|
||||||
@asyncio.coroutine
|
async def index_forbid(request):
|
||||||
def index_forbid(request):
|
|
||||||
return web.HTTPOk()
|
return web.HTTPOk()
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'UserID')
|
await remember(request, response, 'UserID')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def logout(request):
|
||||||
def logout(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
|
@ -258,27 +225,27 @@ def test_has_permission(loop, test_client):
|
||||||
app.router.add_route('GET', '/permission/forbid', index_forbid)
|
app.router.add_route('GET', '/permission/forbid', index_forbid)
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
app.router.add_route('POST', '/logout', logout)
|
app.router.add_route('POST', '/logout', logout)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
|
|
||||||
resp = yield from client.get('/permission/read')
|
resp = await client.get('/permission/read')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
resp = yield from client.get('/permission/write')
|
resp = await client.get('/permission/write')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
resp = yield from client.get('/permission/forbid')
|
resp = await client.get('/permission/forbid')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
|
|
||||||
yield from client.post('/login')
|
await client.post('/login')
|
||||||
resp = yield from client.get('/permission/read')
|
resp = await client.get('/permission/read')
|
||||||
assert web.HTTPOk.status_code == resp.status
|
assert web.HTTPOk.status_code == resp.status
|
||||||
resp = yield from client.get('/permission/write')
|
resp = await client.get('/permission/write')
|
||||||
assert web.HTTPOk.status_code == resp.status
|
assert web.HTTPOk.status_code == resp.status
|
||||||
resp = yield from client.get('/permission/forbid')
|
resp = await client.get('/permission/forbid')
|
||||||
assert web.HTTPForbidden.status_code == resp.status
|
assert web.HTTPForbidden.status_code == resp.status
|
||||||
|
|
||||||
yield from client.post('/logout')
|
await client.post('/logout')
|
||||||
resp = yield from client.get('/permission/read')
|
resp = await client.get('/permission/read')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
resp = yield from client.get('/permission/write')
|
resp = await client.get('/permission/write')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
resp = yield from client.get('/permission/forbid')
|
resp = await client.get('/permission/forbid')
|
||||||
assert web.HTTPUnauthorized.status_code == resp.status
|
assert web.HTTPUnauthorized.status_code == resp.status
|
||||||
|
|
|
@ -1,42 +1,34 @@
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_security import authorized_userid, permits
|
from aiohttp_security import authorized_userid, permits
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_authorized_userid(loop, test_client):
|
||||||
def test_authorized_userid(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
userid = await authorized_userid(request)
|
||||||
userid = yield from authorized_userid(request)
|
|
||||||
assert userid is None
|
assert userid is None
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_permits(loop, test_client):
|
||||||
def test_permits(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
ret = await permits(request, 'read')
|
||||||
ret = yield from permits(request, 'read')
|
|
||||||
assert ret
|
assert ret
|
||||||
ret = yield from permits(request, 'write')
|
ret = await permits(request, 'write')
|
||||||
assert ret
|
assert ret
|
||||||
ret = yield from permits(request, 'unknown')
|
ret = await permits(request, 'unknown')
|
||||||
assert ret
|
assert ret
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
|
@ -1,42 +1,34 @@
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from aiohttp_security import remember, forget
|
from aiohttp_security import remember, forget
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_remember(loop, test_client):
|
||||||
def test_remember(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def do_remember(request):
|
||||||
def do_remember(request):
|
|
||||||
response = web.Response()
|
response = web.Response()
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
app.router.add_route('POST', '/', do_remember)
|
app.router.add_route('POST', '/', do_remember)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.post('/')
|
resp = await client.post('/')
|
||||||
assert 500 == resp.status
|
assert 500 == resp.status
|
||||||
assert (('Security subsystem is not initialized, '
|
assert (('Security subsystem is not initialized, '
|
||||||
'call aiohttp_security.setup(...) first') ==
|
'call aiohttp_security.setup(...) first') ==
|
||||||
resp.reason)
|
resp.reason)
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_forget(loop, test_client):
|
||||||
def test_forget(loop, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def do_forget(request):
|
||||||
def do_forget(request):
|
|
||||||
response = web.Response()
|
response = web.Response()
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
|
|
||||||
app = web.Application(loop=loop)
|
app = web.Application(loop=loop)
|
||||||
app.router.add_route('POST', '/', do_forget)
|
app.router.add_route('POST', '/', do_forget)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.post('/')
|
resp = await client.post('/')
|
||||||
assert 500 == resp.status
|
assert 500 == resp.status
|
||||||
assert (('Security subsystem is not initialized, '
|
assert (('Security subsystem is not initialized, '
|
||||||
'call aiohttp_security.setup(...) first') ==
|
'call aiohttp_security.setup(...) first') ==
|
||||||
resp.reason)
|
resp.reason)
|
||||||
yield from resp.release()
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
@ -13,12 +12,10 @@ from aiohttp_session import setup as setup_session
|
||||||
|
|
||||||
class Autz(AbstractAuthorizationPolicy):
|
class Autz(AbstractAuthorizationPolicy):
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def permits(self, identity, permission, context=None):
|
||||||
def permits(self, identity, permission, context=None):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def authorized_userid(self, identity):
|
||||||
def authorized_userid(self, identity):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,81 +27,67 @@ def make_app(loop):
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_remember(make_app, test_client):
|
||||||
def test_remember(make_app, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def handler(request):
|
||||||
def handler(request):
|
|
||||||
response = web.Response()
|
response = web.Response()
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
session = await get_session(request)
|
||||||
session = yield from get_session(request)
|
|
||||||
assert session['AIOHTTP_SECURITY'] == 'Andrew'
|
assert session['AIOHTTP_SECURITY'] == 'Andrew'
|
||||||
return web.HTTPOk()
|
return web.HTTPOk()
|
||||||
|
|
||||||
app = make_app()
|
app = make_app()
|
||||||
app.router.add_route('GET', '/', handler)
|
app.router.add_route('GET', '/', handler)
|
||||||
app.router.add_route('GET', '/check', check)
|
app.router.add_route('GET', '/check', check)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
resp = yield from client.get('/check')
|
resp = await client.get('/check')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_identify(make_app, test_client):
|
||||||
def test_identify(make_app, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def create(request):
|
||||||
def create(request):
|
|
||||||
response = web.Response()
|
response = web.Response()
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def check(request):
|
||||||
def check(request):
|
|
||||||
policy = request.app[IDENTITY_KEY]
|
policy = request.app[IDENTITY_KEY]
|
||||||
user_id = yield from policy.identify(request)
|
user_id = await policy.identify(request)
|
||||||
assert 'Andrew' == user_id
|
assert 'Andrew' == user_id
|
||||||
return web.Response()
|
return web.Response()
|
||||||
|
|
||||||
app = make_app()
|
app = make_app()
|
||||||
app.router.add_route('GET', '/', check)
|
app.router.add_route('GET', '/', check)
|
||||||
app.router.add_route('POST', '/', create)
|
app.router.add_route('POST', '/', create)
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
resp = yield from client.post('/')
|
resp = await client.post('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
resp = yield from client.get('/')
|
resp = await client.get('/')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def test_forget(make_app, test_client):
|
||||||
def test_forget(make_app, test_client):
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def index(request):
|
||||||
def index(request):
|
session = await get_session(request)
|
||||||
session = yield from get_session(request)
|
|
||||||
return web.HTTPOk(text=session.get('AIOHTTP_SECURITY', ''))
|
return web.HTTPOk(text=session.get('AIOHTTP_SECURITY', ''))
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def login(request):
|
||||||
def login(request):
|
|
||||||
response = web.HTTPFound(location='/')
|
response = web.HTTPFound(location='/')
|
||||||
yield from remember(request, response, 'Andrew')
|
await remember(request, response, 'Andrew')
|
||||||
return response
|
return response
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def logout(request):
|
||||||
def logout(request):
|
|
||||||
response = web.HTTPFound('/')
|
response = web.HTTPFound('/')
|
||||||
yield from forget(request, response)
|
await forget(request, response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
app = make_app()
|
app = make_app()
|
||||||
|
@ -112,18 +95,16 @@ def test_forget(make_app, test_client):
|
||||||
app.router.add_route('POST', '/login', login)
|
app.router.add_route('POST', '/login', login)
|
||||||
app.router.add_route('POST', '/logout', logout)
|
app.router.add_route('POST', '/logout', logout)
|
||||||
|
|
||||||
client = yield from test_client(app)
|
client = await test_client(app)
|
||||||
|
|
||||||
resp = yield from client.post('/login')
|
resp = await client.post('/login')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
assert str(resp.url).endswith('/')
|
assert str(resp.url).endswith('/')
|
||||||
txt = yield from resp.text()
|
txt = await resp.text()
|
||||||
assert 'Andrew' == txt
|
assert 'Andrew' == txt
|
||||||
yield from resp.release()
|
|
||||||
|
|
||||||
resp = yield from client.post('/logout')
|
resp = await client.post('/logout')
|
||||||
assert 200 == resp.status
|
assert 200 == resp.status
|
||||||
assert str(resp.url).endswith('/')
|
assert str(resp.url).endswith('/')
|
||||||
txt = yield from resp.text()
|
txt = await resp.text()
|
||||||
assert '' == txt
|
assert '' == txt
|
||||||
yield from resp.release()
|
|
||||||
|
|
Loading…
Reference in New Issue