emmett-framework / emmett

The web framework for inventors
Other
1.06k stars 71 forks source link

Bug in session? #424

Closed josejachuf closed 2 years ago

josejachuf commented 2 years ago

I get an error here [1]

data = pickle.dumps(sdict(current.session)) TypeError: 'NoneType' object is not callable

But all the objects and variables involved contains data, in no case is it None

current.session has data, sdict and pickle existed

emmett 2.4.3 emmett-crypto 0.2.2 emmett-rest 1.3.2

[1] https://github.com/emmett-framework/emmett/blob/8bf5c23c33a0fbdad260789baa6c28e1657bd2e6/emmett/sessions.py#L141

gi0baro commented 2 years ago

@josejachuf sounds quite strange. I know session data is quite sensitive, but is there any chance for you to share session contents (even in a filtered way)? I suspect something ended up in session but is not pickable..

josejachuf commented 2 years ago

Hi @gi0baro, this is I what have

current.session: <sdict {'auth': <sdict {'user': <Row {'id': 1, 'created_at': datetime.datetime(2022, 2, 2 2, 15, 59, 4), 'updated_at': datetime.datetime(2022, 2, 22, 15, 59, 4), 'email': '***', 'registration _key': '', 'reset_password_key': '', 'registration_id': '', 'first_name': 'Jose', 'last_name': 'Jachuf', 'avatar': None, 'institucion': 1, 'roles': ['administrador', 'supervisor', 'impersonate']}>, 'last_visit': datetime.datetime( 2022, 3, 3, 18, 31, 20, 263840), 'last_dbcheck': datetime.datetime(2022, 3, 3, 18, 31, 20, 263840), 'expiration': 3 600, 'remember': False}>}>

sdict(current.session): <sdict {'auth': <sdict {'user': <Row {'id': 1, 'created_at': datetime.datetime(202 2, 2, 22, 15, 59, 4), 'updated_at': datetime.datetime(2022, 2, 22, 15, 59, 4), 'email': '***', 'regis tration_key': '', 'reset_password_key': '', 'registration_id': '', 'first_name': 'Jose', 'last_name': 'Jachuf', 'av atar': None, 'institucion': 1, 'roles': ['administrador', 'supervisor', 'impersonate']}>, 'last_visit': datetime.da tetime(2022, 3, 3, 18, 31, 20, 263840), 'last_dbcheck': datetime.datetime(2022, 3, 3, 18, 31, 20, 263840), 'expirat ion': 3600, 'remember': False}>}>

gi0baro commented 2 years ago

@josejachuf it seems to me the only possible explanation is pickle cannot serialize the Row object. This will require a bit of investigation from my side, gonna update you once I have news.

josejachuf commented 2 years ago

Hi @gi0baro

The same app with:

emmett 2.3.1 emmett-rest 1.2.0

works fine

and with:

emmett 2.4.3 emmett-crypto 0.2.2 emmett-rest 1.3.2

failure. I try with encryption_mode modern and legacy and always fail

gi0baro commented 2 years ago

@josejachuf I can't reproduce your issue.

Can you provide any/all of the following:

The only difference between 2.3 and 2.4 I can think of that might be involved is that rows coming from models (and thus also the one pickled by auth in session) are now a different class (https://github.com/emmett-framework/emmett/blob/master/emmett/orm/models.py#L1087) which defines its own __getstate__ and __setstate__ methods used by pickle. But I don't get what your user class might contain to break it.

josejachuf commented 2 years ago

[Python38] It is for an API REST. The login works well, in fact I get the user For the login I use:

user = auth.login(email=email, password=password)

User Model:

class User(AuthUser):
    tablename = 'auth_users'
    belongs_to({'institucion': 'Institucion'})

    avatar = Field.upload(autodelete=True)

    @rowattr('nombre_completo')
    def _nombre_completo(self, row):
        return '%s %s' % (row.last_name, row.first_name)

    form_labels = {
        'email': 'Correo Electrónico',
        'password': 'Contraseña',
        'first_name': 'Nombre',
        'last_name': 'Apellido',
    }

    validation = {
        'password': {'len': {'gte': 6, 'lte': 256},
                     'message': 'Ingrese entre 6 y 256 caracteres'
                     }
    }

    rest_rw = {
        'institucion': True,
        'registration_key': True
    }
app.pipeline = [
    SessionManager.cookies('3253c0e2-f5b7-4a01',
                           encryption_mode='legacy'
                           ),
    db.pipe,
    auth.pipe,
]

In this way with legacy I get this error:

Traceback (most recent call last): File "/venv/lib/python3.8/site-packages/emmett/asgi/handlers.py", line 325, in dynamic_handler http = await self.router.dispatch(ctx.request, ctx.response) File "/venv/lib/python3.8/site-packages/emmett/routing/router.py", line 249, in dispatch return await match.dispatch(reqargs, response) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py", line 70, in dispatch await self._parallel_flow(self.flow_open) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py", line 30, in _parallel_flow raise task.exception() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 78, in open_request current.session = self._load_session(current.request) File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 164, in _load_session return self._decrypt_data(cookie_data) File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 148, in _decrypt_data_legacy secure_loads(data, self.key, compression_level=self.compression_level), File "/venv/lib/python3.8/site-packages/emmett/security.py", line 166, in secure_loads return pickle.loads(data) File "/venv/lib/python3.8/site-packages/emmett/orm/models.py", line 1125, in setstate self.dict.update(state["data"]) KeyError: 'data'

whit modern

Traceback (most recent call last): File "/venv/lib/python3.8/site-packages/emmett/asgi/handlers.py", line 325, in dynamic_handler http = await self.router.dispatch(ctx.request, ctx.response) File "/venv/lib/python3.8/site-packages/emmett/routing/router.py", line 249, in dispatch return await match.dispatch(reqargs, response) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py", line 74, in dispatch await self._parallel_flow(self.flow_close) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py", line 30, in _parallel_flow raise task.exception() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 90, in close_request self._pack_session(expiration) File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 61, in _pack_session current.response.cookies[self.cookie_name] = self._session_cookie_data() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 170, in _session_cookie_data return self._encrypt_data() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 141, in _encrypt_data_modern data = pickle.dumps(sdict(current.session)) TypeError: 'NoneType' object is not callable

If I return to emmett 2.3.1 works fine

Jose

gi0baro commented 2 years ago

@josejachuf I was able to reproduce the bug. It involves belongs relations on user model. Gonna work on a solution for this and release a patch for 2.4.

gi0baro commented 2 years ago

@josejachuf this is fixed in 2.4.4

josejachuf commented 2 years ago

Thanks very much

josejachuf commented 2 years ago

Hi @gi0baro, now error it is

ERROR in handlers [/venv/lib/python3.8/site-packages/emmett/asgi/hand lers.py:340]: Application exception: Traceback (most recent call last): File "/venv/lib/python3.8/site-packages/emmett/asgi/handlers.py", lin e 325, in dynamic_handler http = await self.router.dispatch(ctx.request, ctx.response) File "/venv/lib/python3.8/site-packages/emmett/routing/router.py", li ne 249, in dispatch return await match.dispatch(reqargs, response) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py ", line 74, in dispatch await self._parallel_flow(self.flow_close) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py ", line 30, in _parallel_flow raise task.exception() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 90, in close_request self._pack_session(expiration) File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 61, in _pack_session current.response.cookies[self.cookie_name] = self._session_cookie_data() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 170 , in _session_cookie_data return self._encrypt_data() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 141 , in _encrypt_data_modern data = pickle.dumps(sdict(current.session)) AttributeError: Can't pickle local object 'attempt_upload_on_insert..wrapped' INFO: 127.0.0.1:46254 - "POST /main/api/authsm/login HTTP/1.1" 500 Internal Server Error

gi0baro commented 2 years ago

@josejachuf it doesn't really make sense to me. Seems it tries to serialize a Model instance. Is the session still the same, or do you added anything into the model?

josejachuf commented 2 years ago

@gi0baro During the day I will upload the code that I have. But no, I did not change the model

josejachuf commented 2 years ago

backend-bug.zip

Hi @gi0baro This already fails with Emmett 2.4 with 2.3 works fine

curl -X POST http://127.0.0.1:8000/main/api/authsm/login -H 'Content-Type: application/json' -d '{"email": "doc@emmettbrown.com","password":"123456"}'

gi0baro commented 2 years ago

@josejachuf found the bug thanks to the code you posted. Gonna work on it and produce a new patch version in the next few days

gi0baro commented 2 years ago

@josejachuf this is now fixed in 2.4.5 Thank you for your patience.

josejachuf commented 2 years ago

Thank you very much, until now everything works fine

josejachuf commented 2 years ago

Hi @gi0baro

Again, an error occurs with sessions with version 2.4.7

Traceback (most recent call last): File "/venv/lib/python3.8/site-packages/emmett/asgi/handlers.py", line 325, in dynamic_handler http = await self.router.dispatch(ctx.request, ctx.response) File "/venv/lib/python3.8/site-packages/emmett/routing/router.py", line 249, in dispatch return await match.dispatch(reqargs, response) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py", line 74, in dispatch await self._parallel_flow(self.flow_close) File "/venv/lib/python3.8/site-packages/emmett/routing/dispatchers.py", line 30, in _parallel_flow raise task.exception() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 90, in close_request self._pack_session(expiration) File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 61, in _pack_session current.response.cookies[self.cookie_name] = self._session_cookie_data() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 170, in _session_cookie_data return self._encrypt_data() File "/venv/lib/python3.8/site-packages/emmett/sessions.py", line 141, in _encrypt_data_modern data = pickle.dumps(sdict(current.session)) AttributeError: Can't pickle local object 'attempt_upload_on_insert..wrapped'

You can try with: https://github.com/emmett-framework/emmett/files/8207695/backend-bug.zip

curl -X POST http://127.0.0.1:8000/main/api/authsm/login -H 'Content-Type: application/json' -d '{"email": "doc@emmettbrown.com](mailto:doc@emmettbrown.com)","password":"123456"}'

Jose

gi0baro commented 2 years ago

@josejachuf I officially hate this. My bad I didn't add a test for this. Gonna address this properly this time.

josejachuf commented 2 years ago

No problem. I am in stage of development and I can use the old version

gi0baro commented 2 years ago

@josejachuf fixed in 2.4.8

josejachuf commented 2 years ago

This works fine. Thanks!