Giter VIP home page Giter VIP logo

aiohttp-session's People

Contributors

achernetsky avatar alexander-travov avatar alexkovalevych avatar alexpantyukhin avatar amenezes avatar asvetlov avatar bfriedrichs avatar bmwant avatar carlopires avatar dependabot-preview[bot] avatar dependabot[bot] avatar dreamsorcerer avatar fafhrd91 avatar gleb-chipiga avatar gomzik avatar graingert avatar gyermolenko avatar imbolc avatar jettify avatar mariatta avatar minamorl avatar mind1m avatar oleksandr-kuzmenko avatar panagiks avatar pelson avatar pwntester avatar pyup-bot avatar shicky avatar smialy avatar webknjaz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aiohttp-session's Issues

Makefile depends on Python 2 with setuptools

I'm trying to build aiohttp and aiohttp-session under Yocto. It tries to run make clean as part of the build process. make clean runs python setup.py clean. But that runs Python 2, and that fails because the build system doesn't have Python 2 with setuptools installed.

Since aiohttp is Python 3 only, would it make more sense for the Makefile to run python3 make clean instead, to avoid such unusual Python 2 dependencies?

Session Fixation vulnerability in RedisStorage

There is a window of opportunity for Session Fixation exploitation in the logic of RedisStorage.

As seen here: https://github.com/aio-libs/aiohttp-session/blob/master/aiohttp_session/__init__.py#L190

Get session data returns an empty dictionary for an empty (this includes invalidated) session.

Referring here: https://github.com/aio-libs/aiohttp-session/blob/master/aiohttp_session/redis_storage.py#L60

save_session takes this data and saves it in Redis.

As a result, an invalidated session will result to the session ID being present in Redis with an empty mapping as its value.

Now looking over at: https://github.com/aio-libs/aiohttp-session/blob/master/aiohttp_session/redis_storage.py#L50

RedisStorage's load_session only looks at the case where data (returned by reading from Redis) is None. This will happen only if the key (session ID) is not present in Redis (has either expired or was never inserted) but as we established above the key is never actually removed, just the value mapping emptied. As a result the load_session function will return a session with the presented session ID and not a new one, although there was no valid session in storage for this ID.

If this is not caught and mitigated by the web app the following scenario can unfold:

  • Attacker acquires a valid cookie
  • Invalidates it (logs out)
  • Attacker injects said cookie in victim's browser (see OWASP's link above for examples on how)
  • Victim visits web app presenting the cookie present in his browser
  • Web app uses the get_session to get a session object for the user, expecting a 'clean' session
  • get_session returns a session with the session ID that was present in the cookie presented by the user
  • session is populated by the web app and subsequently stored by aiohttp-session during the response
  • User is now logged in with the session ID of the cookie that was injected by the attacker
  • The attacker now controls (knows) a session cookie for a given user

pip install FileNotFoundError

pip install crashed with strace:

(VENV) crwnlssmbp:aiohttp-session soullu$ python ./setup.py install
Traceback (most recent call last):
File "./setup.py", line 27, in
long_description='\n\n'.join((read('README.rst'), read('CHANGES.txt'))),
File "./setup.py", line 16, in read
return open(os.path.join(os.path.dirname(file), f)).read().strip()
FileNotFoundError: [Errno 2] No such file or directory: './CHANGES.txt'

AttributeError: 'Response' object has no attribute 'started'

I'm using version 0.5.0 with python 3.6. I've followed the example code and am using the cookie storage. I keep getting the error AttributeError: 'Response' object has no attribute 'started' in aiohttp_session/__init__.py", line 138, in middleware.

Here is my set up code.

app = web.Application()

aiohttp_jinja2.setup(
    app, loader=jinja2.FileSystemLoader('MyApp/templates')
)

fernet_key = fernet.Fernet.generate_key()
secret_key = base64.urlsafe_b64decode(fernet_key)
setup(app, EncryptedCookieStorage(secret_key))

web.run_app(app, port=8000)

the error occurs only when I try to load any page registerd in the app.

Yum broken when RPM from this requirement with underscores.

Please never use underscores in python-packages names.

PEP-008 conatins

Python packages should also have short, all-lowercase names, although the use of underscores is discouraged.

We have a really problem. When our build system convert all dependencies to RPM (using FPM) yum is broken. We are can't use this package in our projects.

redis storage error

Hi, i have some error when add value to session.

ERROR:aiohttp.server:Error handling request
Traceback (most recent call last):
  File "/home/ubuntu/chat/env/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 410, in start
    resp = yield from self._request_handler(request)
  File "/home/ubuntu/chat/env/lib/python3.6/site-packages/aiohttp/web.py", line 326, in _handle
    resp = yield from handler(request)
  File "/home/ubuntu/chat/env/lib/python3.6/site-packages/aiohttp/web_middlewares.py", line 93, in impl
    return (yield from handler(request))
  File "/home/ubuntu/chat/env/lib/python3.6/site-packages/aiohttp_session/__init__.py", line 144, in middleware
    yield from storage.save_session(request, response, session)
  File "/home/ubuntu/chat/env/lib/python3.6/site-packages/aiohttp_session/redis_storage.py", line 60, in save_session
    with (yield from self._redis) as conn:
TypeError: 'ConnectionsPool' object is not iterable

Q: uuid4 vs urandom(16) for Redis keys

This is more of question than an issue (and maybe not even specific to aiohttp_session), but I was wondering why are the keys using uuid4 when codecs.encode(urandom(16), 'hex') would suffice?
Is it just a preference or is there some deeper reason?

Add the ability set `identity` of session if it is `new`

Hello,

What do you think about it?

I need set identity, which used how key in redis, of session with custom key. And then I need remove session by that identity from redis by message from amqp with this identity.

Now identity readonly property.

Example code

class LoginView(BaseView):
   async def post(self):
       session = await aiohttp_session.get_session(self.request)
       if session.new:
           session.identity = 'key'
       session['user'] = {...}

Thanks.

Non-cookie-based client-server session contract

Hi!

Is there a strong reason why aiohttp_session in its internal API relies strictly on cookies as the only medium to communicate session information to/from clients (https://github.com/aio-libs/aiohttp_session/blob/master/aiohttp_session/__init__.py#L160-L216)?

For instance, I can think of a REST API workflow that uses HTTP headers to provide both a session token and a csrf-preventing token. But in order to implement that kind of API contract, I have to either rely on my own version of a session-handling middleware (that would be about 98-99% similar to aiohttp_session), or go with wrappers around aiohttp_session that extract necessary pieces of information from set cookies and send them in different formats to the client.

I can also think of a possible improvement over that rigidity, by delegating the final implementation of how clients and a server exchange session credentials to a "proxy" ClientServerContract object, that would be constructed during the app initialization step and then used consistently by AbstractStorage (and its derivatives).

Redis storage breaks with aioredis 1.0

2017-11-20 03:35:36,263 ERROR    aiohttp.server Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/aiohttp/web_protocol.py", line 416, in start
    resp = yield from self._request_handler(request)
  File "/usr/local/lib/python3.6/site-packages/aiohttp/web.py", line 323, in _handle
    resp = yield from handler(request)
  File "/usr/local/lib/python3.6/site-packages/aiohttp_session/__init__.py", line 142, in factory
    yield from storage.save_session(request, response, session)
  File "/usr/local/lib/python3.6/site-packages/aiohttp_session/redis_storage.py", line 60, in save_session
    with (yield from self._redis) as conn:
TypeError: 'ConnectionsPool' object is not iterable

There are breaking changes in aioredis 1.0, especially Python 3.3, 3.4 supports are dropped, See https://github.com/aio-libs/aioredis/releases/tag/v1.0.0

May be fixed by limiting the aioredis version or upgrading to the new API?

[Feature] Requesting new session explicitly

General

I think aiohttp-session should provide a way to explicitly request a new session, ignoring the existence of a cookie.

Implementation

My initial thought is to pass an optional kwarg new=True to get_session, which in turn will pass it to the storage's load_session function to force it to return a new Session ignoring the presence of any cookie.

Background

This is another window for Session Fixation, although this does not affect aiohttp-session itself like #272 but the application logic. I think that providing a way to explicitly request a new session (and encouraging the use of it in documentation and examples related to login functionality) would greatly benefit the users of aiohttp-session in terms of writing more secure code.

Looking into OWASP's entry for Session Fixation:

When authenticating a user, it [the vulnerable web application] doesn’t assign a new session ID, making it possible to use an existent session ID.

@asvetlov do you agree with adding this feature ? If so I can have a PR ready during the weekend (to also add documentation and usage examples).

[Suggestion][middleware] Add flag to silence storage exceptions

Would it be in scope of the project to add the option to silence Exceptions raised during storage.save_session that happens here?

My reasoning is that if you have a long-running or computationally expensive request that completed successfully you wouldn't want to loose your response (since a raise at that point means that the response will not be available to the upper middleware) if for example a write that renews the last visit value of a user's session fails (insert any other non-essential info stored in a session).

Alternatively could we add a new Exception Class that will have the response as an attribute (so an upper middleware can still access the response)? Or add the attribute to the caught exception and re-raise it?

Also open for any other suggestions as to how the response could be preserved in case a raise occurs during storage.save_session.

Could/should an expired cookie be returned on session.invalidate

Hello,

let me start by thanking you for a great library that has saved me tons of time :)

Now on to the matter at hand. A lot of web services (and mainly websites) return an expired version of the logged in user's cookie upon logout. This helps since most browsers will delete expired cookies and the front-end doesn't have to bother with cookie management.

Is a feature like this, for example returning an expired cookie after session.invalidate, a) technically feasible and b) something that you would consider as a possible addition ?

Thank you for you time and thanks again for a great library :)

Why the example code always fail to run???

You must feel frustrated, if you try a new thing but fail in the simplest way. I run this code in windows 32 system.
the code is the example you give.
`
import asyncio
import time
from aiohttp import web
from aiohttp_session import get_session, session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage

@asyncio.coroutine
def handler(request):
session = yield from get_session(request)
session['last_visit'] = time.time()
return web.Response(body=b'OK')

@asyncio.coroutine
def init(loop):
app = web.Application(middlewares=[session_middleware(
EncryptedCookieStorage(b'1111'))])
app.router.add_route('GET', '/', handler)
srv = yield from loop.create_server(
app.make_handler(), '0.0.0.0', 8080)
return srv

loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
`

Not able to invalidate session, using EncryptedCookieStorage

These lines https://github.com/aio-libs/aiohttp_session/blob/master/aiohttp_session/__init__.py#L161-L162 will never be executed in case of usage EncryptedCookieStorage:

Here https://github.com/aio-libs/aiohttp_session/blob/master/aiohttp_session/cookie_storage.py#L43-L47
in case of empty dict session._mapping variable cookie_data is b'{} ' and after all transformations b64coded is a hash which is definitely not a False boolean value.

As result condition if not cookie_data: will always return False and session will not be invalidated.

Description of max_age=None looks wrong

The docs says "max_age - Maximum age for session data, int seconds or None for infinite session.". But in reality session with max_age=None lives until browser is closed.

Remove session key from redis by session.invalidate

Hello,

Actual behaviour

Key from redis does not deleted after session is invalidate.

Expected behaviour

Key from redis deleted after session is invalidate.

What do you think about it?

class LogoutView(BaseView):
   async def post(self):
       session = await aiohttp_session.get_session(self.request)
       session.invalidate()

Thanks.

Tests are failing!

Hi!
Tests of test_response_types.py arn't pass!
Is this problem just for me?
I'm using Python 3.5.2.

Fail silently when no key available in session storage

Let's imagine standart approach for getting user ID from request session:

@asyncio.coroutine
def get_request_user(request):
    session = yield from get_session(request)
    user_id = session.get(SESSION_USER_KEY)

    if not user_id:
        return None

    ...

But with aiohttp_session==0.1.1 this makes no sense as session.get returns session storage instance instead of looking up for key in _mapping dict. Currenlty in this case I need to use:

    try:
         user_id = session[SESSION_USER_KEY]
    except KeyError:
         return None

or even

    user_id = session._mapping.get(SESSION_USER_KEY)

but really prefer to have get, setdefault, and update methods overriden in session storage, so don't need to call them with _mapping attribute.

What do you think?

Support custom JSON encoder/decoder

When i try do

session = yield from get_session(self.request)
session['user'] = user

with user is a document of mongo, my program occur a error:

Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.4/dist-packages/aiohttp/server.py", line 266, in start
    yield from self.handle_request(message, payload)
  File "/usr/local/lib/python3.4/dist-packages/aiohttp/web.py", line 90, in handle_request
    resp = yield from handler(request)
  File "/usr/local/lib/python3.4/dist-packages/aiohttp_session/__init__.py", line 144, in middleware
    yield from storage.save_session(request, response, session)
  File "/usr/lib/python3.4/asyncio/coroutines.py", line 141, in coro
    res = func(*args, **kw)
  File "/usr/local/lib/python3.4/dist-packages/aiohttp_session/cookie_storage.py", line 52, in save_session
    self._get_session_data(session)
  File "/usr/lib/python3.4/json/__init__.py", line 230, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python3.4/json/encoder.py", line 192, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.4/json/encoder.py", line 250, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python3.4/json/encoder.py", line 173, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: ObjectId('56d07ade0686372f8e45b3f1') is not JSON serializable

How do i replace 'json' encoder with 'bson.json_until' encoder?
https://github.com/aio-libs/aiohttp_session/blob/master/aiohttp_session/cookie_storage.py#L51

Cannot decrypt cookie value, create a new fresh session

Repeat the refresh page, with such errors, sometimes without

` class WorkerPool:
    def __init__(self, loop):
        self.loop = asyncio.get_event_loop() or loop
        self.webRouter = WebRoute(loop = loop)

    async def init(self):
        '''
        app = Application(loop=self.loop)
        fernet_key = fernet.Fernet.generate_key()
        secret_key = base64.urlsafe_b64decode(fernet_key)
        setup(app, EncryptedCookieStorage(secret_key))

        app.router.add_static('/static/',path=str(PROJECT_ROOT / 'static'),name='static')
        aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader(template_dir))
        self.webRouter.base(app)
        return app

try:
    loop = asyncio.get_event_loop()
    wp = WorkerPool(loop=loop)
    app =loop.run_until_complete(wp.init())

except KeyboardInterrupt:
    sys.stderr.flush()

`

[Redis] Sentinel Pool support

As it seems from Issue 185 and some references in documentation aioredis will be adding Sentinel support in V1.0.
Is it within the project's scope to support both connection pools and sentinel pools?

If so I'd like to take a swing at implementing this feature once aioredis version that includes the feature is released.

Also should we choose to implement this I can already see tests being a bit tricky (not so much on the python side but more on the 'we will need to have a redis cluster to test against' side), so any leads in that field would be greatly appreciated.

My initial thought was to completely patch (mock) the class for the Sentinel Pool, but this carries the drawback that our tests will be as accurate as our mock class (i.e. if the mocked class is wrong and the tests are passing).

With max_age set, cookies expire immediately on IE11 or Edge

With max_age set, expiry is calculated using time.gmtime(time.monotonic() + max_age)

I don't think time.monotonic() reliably gives number of seconds since the epoch, so on my server, expiry is calculated to a 1970 date e.g. expires=Sat, 31-Jan-1970 04:52:49 GMT and a user using IE or Edge never gets a cookie. Interestingly Firefox and Chrome ignore the old expires value and the cookie works (I suspect it will never expire).

It seems to work for me to use time.time() in place of time.monotonic() but I wasn't clear on the intention of using the monotonic clock here?

SimpleCookieStorage not working?

First of all, apologies if this is not an issue and I'm just doing something wrong.
Without going into the reason (that is a topic for another potential issue), I am trying to use the SimpleCookieStorage class.

I have a simple server which uses a slightly modified piece of example code. This server works just fine with the EncryptedCookieStorage but it dies when I try and use it with SimpleCookieStorage.
Am I using the class incorrectly?

Server code below:

import asyncio
import time
from aiohttp import web
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_session import setup, get_session, SimpleCookieStorage


import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)

async def handler(request):
    session = await get_session(request)
    last_visit = session.get('last_visit', 'Never')
    if last_visit == 'Never':
        message = "Welcome, I don't think you've visited here before."
    else:
        message = 'Welcome back, last visited: {} secs ago'.format(time.time() -
                last_visit)
    session['last_visit'] = time.time()

    return web.Response(body=message.encode('utf-8'))

async def init(loop):
    app = web.Application()
    setup(app, SimpleCookieStorage())
    #setup(app, EncryptedCookieStorage(b'Thirty  two  length  bytes  key.'))
    app.router.add_route('GET', '/', handler)
    srv = await loop.create_server(
        app.make_handler(), '0.0.0.0', 8080)
    return srv

loop = asyncio.get_event_loop()
loop.run_until_complete(init(loop))
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

To make this code work, I can just comment the line invoking SimpleCookieStorage and uncomment the one invoking EncryptedCookieStorage.

The traceback I get when using the SimpleCookiStorage class is:

Error handling request
Traceback (most recent call last):
  File "c:\projects\aio-rpc\venv\lib\site-packages\aiohttp\server.py", line 285, in start
    yield from self.handle_request(message, payload)
  File "c:\projects\aio-rpc\venv\lib\site-packages\aiohttp\web.py", line 90, in handle_request
    resp = yield from handler(request)
  File "c:\projects\aio-rpc\venv\lib\site-packages\aiohttp_session\__init__.py", line 129, in middleware
    response = yield from handler(request)
  File "server.py", line 12, in handler
    session = await get_session(request)
  File "c:\projects\aio-rpc\venv\lib\site-packages\aiohttp_session\__init__.py", line 107, in get_session
    session = yield from storage.load_session(request)
  File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\envs\py35\lib\asyncio\coroutines.py", line 206, in coro
    res = func(*args, **kw)
  File "c:\projects\aio-rpc\venv\lib\site-packages\aiohttp_session\__init__.py", line 237, in load_session
    data = json.loads(cookie)
  File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\envs\py35\lib\json\__init__.py", line 319, in loads
    return _default_decoder.decode(s)
  File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\envs\py35\lib\json\decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "C:\Users\gkuhn\AppData\Local\Continuum\Anaconda3\envs\py35\lib\json\decoder.py", line 357, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

typos in examples

In README, there is:
from cryptorgraphy import fernet - should be cryptography

There is also: Requires crypotgraphy library: with a similar typo.

When trying the first example in README, the trivial usage example, (and after fixing the typo)
I get:

File "c:\projects\asyncio_venv\lib\site-packages\aiohttp\web.py", line 305, in run_app loop = app.loop AttributeError: 'NoneType' object has no attribute 'loop'

I am using python 3.5.2 on Anaconda on Windows

error appears when i would like to use redis session

The project in https://github.com/inzem77/ws-chat

serving on ('0.0.0.0', 8080)
Error handling request
Traceback (most recent call last):
  File "/home/inzem/sites/chat/ENV3.5/lib/python3.5/site-packages/aiohttp/server.py", line 272, in start
    yield from self.handle_request(message, payload)
  File "/home/inzem/sites/chat/ENV3.5/lib/python3.5/site-packages/aiohttp/web.py", line 87, in handle_request
    resp = yield from handler(request)
  File "/home/inzem/sites/chat/ENV3.5/lib/python3.5/site-packages/aiohttp_session/__init__.py", line 138, in middleware
    yield from storage.save_session(request, response, session)
  File "/home/inzem/sites/chat/ENV3.5/lib/python3.5/site-packages/aiohttp_session/redis_storage.py", line 48, in save_session
    with (yield from self._redis) as conn:
AttributeError: __exit__

Error with setup and PyTest

It's probably a collision between names but when you import

from aiohttp_session import setup

in your PyTest you get

self = <CallInfo when='setup' exception: setup() missing 2 required positional arguments: 'app' and 'storage'>, func = <function call_runtest_hook.<locals>.<lambda> at 0x104106ea0>, when = 'setup'

    def __init__(self, func, when):
        #: context of invocation: one of "setup", "call",
        #: "teardown", "memocollect"
        self.when = when
        self.start = time()
        try:
>           self.result = func()

../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/runner.py:163:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/runner.py:151: in <lambda>
    return CallInfo(lambda: ihook(item=item, **kwds), when=when)
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:745: in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:339: in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:334: in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:613: in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:254: in _wrapped_call
    return call_outcome.get_result()
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:279: in get_result
    raise ex[1].with_traceback(ex[2])
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:265: in __init__
    self.result = func()
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/vendored_packages/pluggy.py:614: in execute
    res = hook_impl.function(*args)
../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/nose.py:39: in pytest_runtest_setup
    call_optional(item.parent.obj, 'setup')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

obj = <module 'tests.test_auth' (<_pytest.assertion.rewrite.AssertionRewritingHook object at 0x1033dd780>)>, name = 'setup'

    def call_optional(obj, name):
        method = getattr(obj, name, None)
        isfixture = hasattr(method, "_pytestfixturefunction")
        if method is not None and not isfixture and py.builtin.callable(method):
            # If there's any problems allow the exception to raise rather than
            # silently ignoring them
>           method()
E           TypeError: setup() missing 2 required positional arguments: 'app' and 'storage'

../../../miniconda3/envs/mcc.cassiny.io/lib/python3.5/site-packages/_pytest/nose.py:70: TypeError

Support for cookieless sessions

Hi,

I think there are reasonable use cases where people would like to use sessions when using aiohttp without aiohttp.web or cookies .

For example

  • When using aiohttp/asyncio inside other frameworks and would like to use aiohttp in asynchronous session management
  • When developing something like a chatbot in platforms like messenger platform where cookies are not supported
  • When you want to have some sort of sessions when providing an API consumed by native apps
  • ... etc

I know in a lot of cases standard HTTP sessions are used with cookies but since aiohttp is now being used in very diverse environments may be it would be useful to have at least one session storage backend which can fully function without aiohttp.web.Resquest/Response objects.

Does this sound reasonable?

I am imagining something like the below ("Cookieless Redis Session Storage")

import asyncio
import json
import uuid

from aiohttp_session import AbstractStorage, Session


class RedisCookielessStorage(AbstractStorage):
    """Redis storage"""

    def __init__(self, redis_pool, *, key_prefix="aiohttp_session",
                 domain=None, max_age=None, path='/',
                 secure=None, httponly=True,
                 encoder=json.dumps, decoder=json.loads,
                 key_factory=lambda: uuid.uuid4().hex):
        super().__init__(domain=domain, max_age=max_age, path=path,
                         secure=secure, httponly=httponly)
        self._encoder = encoder
        self._decoder = decoder
        self._key_prefix = key_prefix
        self._key_factory = key_factory
        self._redis = redis_pool

    @property
    def key_prefix(self):
        return self._key_prefix

    @asyncio.coroutine
    def load_session(self, key=None):
        if key is None:
            return Session(None, data=None, new=True, max_age=self.max_age)
        else:
            with (yield from self._redis) as conn:
                data = yield from conn.get(self.key_prefix + ':' + key)
                if data is None:
                    return Session(key, data=None, new=True, max_age=self.max_age)
                data = data.decode('utf-8')
                try:
                    data = self._decoder(data)
                except ValueError:
                    data = None
                return Session(key, data=data, new=False, max_age=self.max_age)

    @asyncio.coroutine
    def save_session(self, session):
        key = session.identity or self._key_factory()
        data = self._encoder(self._get_session_data(session))
        with (yield from self._redis) as conn:
            max_age = session.max_age
            expire = max_age if max_age is not None else 0
            yield from conn.set(self.key_prefix + ':' + key,
                                data, expire=expire)

Then you can do something like

redis = await aioredis.create_pool(('localhost', 6379))
session_storage = RedisCookielessStorage(redis)

session = await session_storage.load_session('<YOUR_SESSION_KEY>')
 ...
await session_storage.save_session(session)

Rewrite tests to use docker

Like aiopg
We need to use dockerized redis and memcache servers in our tests.
It simplifies local development.

React + Session

Hello guys, how to write cookie session to my react app, when i'm in developing mode? I'm syncing data via proxy.
In ideal I'm need to create session on my react app, because when I'm coping cookie to react and trying to read it on server app response with: "Cannot decrypt cookie value, create a new fresh session".

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.