Skip to content

[MIG] auth_session_timeout: Migration to 10.0 - #875

Closed
chienandalu wants to merge 16 commits into
OCA:10.0from
Tecnativa:10.0-mig-inactive_session_timeout
Closed

[MIG] auth_session_timeout: Migration to 10.0#875
chienandalu wants to merge 16 commits into
OCA:10.0from
Tecnativa:10.0-mig-inactive_session_timeout

Conversation

@chienandalu

@chienandalu chienandalu commented Jun 26, 2017

Copy link
Copy Markdown
Member

Auth Session Timeout

This module was written to be able to kill (logout) all inactive sessions since
a given delay. On each request the server checks if the session is yet valid
regarding the expiration delay. If not a clean logout is operated.

cc @Tecnativa

@chienandalu
chienandalu force-pushed the 10.0-mig-inactive_session_timeout branch from 2d41a9a to a848e87 Compare June 26, 2017 13:15
@yajo yajo added this to the 10.0 milestone Jun 27, 2017

@yajo yajo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code needs a small refactor to make it more maintaiable 😉

_inherit = 'ir.config_parameter'

@api.model
@tools.ormcache(skiparg=0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with registry(db).cursor() as cr:
env = Environment(cr, SUPERUSER_ID, {})
param_obj = env['ir.config_parameter']
delay, urls = param_obj.get_session_parameters(db)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, you'll have to change this for 2 calls to ir.config_parameter.get_param if you delete ir_config_parameter.py file as suggested above.

@classmethod
def check(cls, db, uid, passwd):
res = super(ResUsers, cls).check(db, uid, passwd)
cls._check_session_validity(db, uid, passwd)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just move all the code from _check_session_validity into this method? After all this one does nothing more...

Or even better, why not move these checks into check_credentials? That one is a normal method (not a @classmethod) and has a working self.env to work with.

@chienandalu

Copy link
Copy Markdown
Member Author

@yajo Look at it now. Some notes:

  • Seems that _check_session_validity is not going to be called allways. So I took a halfway solution.
  • When the session expires, an exception raises. Do you think is convenient to catch it and explain to the user to reload browser and login again?
  • Besides no update is set in default data, every time I update the module the parameters are reset.

'author': "ACSONE SA/NV, "
"Tecnativa, "
"Odoo Community Association (OCA)",
'website': 'https://www.tecnativa.com',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let original acsone URL.

<?xml version='1.0' encoding='UTF-8' ?>
<odoo>

<data noupdate="1">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 2 data noupdate? Put all in the first tag (<odoo noupdate="1">)

return
session = request.session
session_store = root.session_store
ipm = self.env['ir.config_parameter']

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have removed the other model and it was introduced for having a cache mechanism to not query so many times the DB, so please restore it as it was.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was @yajo 's request, given that get_param has already a cached mechanism at its core: https://github.com/odoo/odoo/blob/10.0/odoo/addons/base/ir/ir_config_parameter.py#L53-L68

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see. Then it's enough indeed. Maybe it would be good to throw a comment saying that this is cached, so no performance penalty...

if getmtime(path) < deadline:
if session.db and session.uid:
session.logout(keep_db=True)
elif http.request.httprequest.path not in urls:

@pedrobaeza pedrobaeza Jun 28, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is totally wrong (not your fault, as it was the same on v8), but the intended behavior for this is not achieved here:

  • This should be checked before doing anything. See that if the request has been inactive, you'll get logout anyway.
  • What you have to check is if one of the ignored path keys (variable urls) is not included in current http request, so the code should be something similar to:
    if any([url in http.request.httprequest.path for x in urls]):
        return

@chienandalu
chienandalu force-pushed the 10.0-mig-inactive_session_timeout branch from b77a623 to 3cdb809 Compare June 29, 2017 09:22
@chienandalu

Copy link
Copy Markdown
Member Author

@pedrobaeza Changes done

deadline = time() - delay
path = session_store.get_session_filename(session.sid)
try:
if any([url in http.request.httprequest.path for url in urls]):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, this is incorrect for 2 reasons:

  1. Performance-wise, doing any([... for ...]) makes the generator be converted in a list and then iterated again under the any. You can save several iterations by just dropping the [] characters. Not critical here since the list will be short, but keep it in mind.
  2. If you have /longpolling,/shop, then a request to /blog/longpolling-is-your-friend will give a false positive.

Instead of this, do:

if any(map(http.request.httprequest.path.startswith, urls)):

@chienandalu

Copy link
Copy Markdown
Member Author

@yajo @pedrobaeza Changes done

self.ipm.set_param(DELAY_KEY, 1)
res = self.rus.authenticate(self.db, 'admin', 'admin', {})
time.sleep(1.1)
res = self.rus.browse(res).check(self.db, res, 'admin')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are actually not checking here anything, and you also don't have any request. Better to put that this is a TODO and include in "Known issues" to finish tests. Or @yajo, do you have a quick suggestion for testing this?

@yajo yajo Jun 30, 2017

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To have full coverage, you can either mock the session or authenticate through an HttpCase.

Also, after this code (that checks you are OK), I'd try mocking also the method that checks if the session time is old to make it think it is, and then check that you are kicked off.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've commited a test with HttpCase but I still don't get a request. Can you provide an example to use as a guideline?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you need to authenticate through an http request to get a working request (redundant, but that's it). Check this out: https://github.com/odoo/odoo/blob/10.0/odoo/tests/common.py#L270

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yajo I still can't see how to do such request 😕

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you try calling that method?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return

@classmethod
def check(cls, db, uid, passwd):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not override this method. Override check_credentials. Raise an AccessDenied if the session is expired.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, the idea is to return to logout, disauthorizing future operations and returning to login

self.assertTrue(self.ipm.get_param(DELAY_KEY), 1)
self.authenticate('admin', 'admin')
time.sleep(1.1)
res = self.rus.browse(1).check(self.db, 1, 'admin')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert that this should raise a AccessDenied exception

@pedrobaeza

Copy link
Copy Markdown
Member

I have just found that the module was renamed to auth_session_timeout in v9. We should rename it too.

@pedrobaeza

Copy link
Copy Markdown
Member

See also #887

@chienandalu

Copy link
Copy Markdown
Member Author

@pedrobaeza Implemented some of the good ideas of #887
7f38887

@lasley

lasley commented Jul 5, 2017

Copy link
Copy Markdown
Contributor

IMO we should complete #887 before a merge of this one just so we make sure we have a proper migration path

@pedrobaeza

Copy link
Copy Markdown
Member

Well, if this one includes the changes of that PR, we assure migration path, isn't it?

@lasley

lasley commented Jul 5, 2017

Copy link
Copy Markdown
Contributor

This is true, however there were some PR review recommendations that I don't think were attended to here. Reviewing and modifying in two PRs seems like duplicating effort IMO (even though I'm totally guilty of submitting multiple active PRs against the same module, so kettle calling the pot black here).

Also, the commit wasn't cherry picked so we've lost attribution + I'm not entirely certain which aspects of #887 were retained because the commit is squashed into another logical one & the comment noted that only some of the good ideas were implemented.

@pedrobaeza

Copy link
Copy Markdown
Member

OK, please try to speed up the other PR and we will wait for this.

@chienandalu

Copy link
Copy Markdown
Member Author

Hi, @lasley. Maybe the confusion has been originated because I didn't realize in first place that there was an already migrated version on v9. So now they have diverged quite a bit. From the last PR, I took the idea of split some of functionalities into separate methods and adapted it to my existing code. Although I've got no objection in giving fair attribution. Anyway I'll wait until the PR is fully reviewed 😃 👍

@chienandalu chienandalu changed the title [MIG] inactive_session_timeout: Migration to 10.0 [MIG] auth_session_timeout: Migration to 10.0 Aug 30, 2017
@pedrobaeza

Copy link
Copy Markdown
Member

Closing in favor of #580

@pedrobaeza pedrobaeza closed this Sep 6, 2017
@pedrobaeza
pedrobaeza deleted the 10.0-mig-inactive_session_timeout branch September 6, 2017 10:45
@lasley

lasley commented Sep 6, 2017

Copy link
Copy Markdown
Contributor

😆 did I seriously review a module that I also had an open PR for? whoops

SiesslPhillip pushed a commit to grueneerde/OCA-server-tools that referenced this pull request Nov 20, 2024
Syncing from upstream OCA/server-tools (15.0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants