Module auth_session_timeout: Pluggability - #887
Conversation
jmorgannz
commented
Jul 5, 2017
- Refactor to allow other modules to inherit and augment or override the following:
- Session expiry time (deadline) calculation
- Ignored URLs
- Final session expiry (with possibility to late-abort)
- Re-ordered functionality to remove unnecessary work, as this code is called very often.
- Do not expire a session if delay gets set to zero (or unset / false)
--------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false)
|
Hey @jmorgannz, thank you for your Pull Request. It looks like some users haven't signed our Contributor License Agreement, yet.
Appreciation of efforts, |
|
I'm new at this (contributing); guess I might need to read up on the CLA. I didn't want to re-implement the entire thing, but the OCA copy was not easily pluggable. I am using this in production. |
lasley
left a comment
There was a problem hiding this comment.
Thanks for the contribution @jmorgannz!
Information on the CLA is here. Let us know if you have questions.
I added some comments inline after reviewing. Also, it would be nice to see some tests for your added logic - we're dropping in coverage here.
| @@ -1,5 +1,5 @@ | |||
| # -*- coding: utf-8 -*- | |||
| # (c) 2015 ACSONE SA/NV, Dhinesh D | |||
| # (c) 2015 ACSONE SA/NV, Dhinesh D, Jesse Morgan | |||
There was a problem hiding this comment.
Please do not append to others' copyrights. Also, you did not change this file at all, so your claim to copyright on any aspect of it would be invalid.
Regarding the copyright headers & what happened here - we were significantly more lax on what happened with these headers previously. If you look at the history of this file, you'll see that Dhinesh D's copyright is actually invalid here too & I would argue it is invalid for the entire module. That argument isn't something to make for history though, but it's most certainly something to enforce going forwards.
Typically if you're going to claim copyright on a file in the header, you need to have written the whole thing. Otherwise, Git line-by-line attribution is an implicit copyright on things you do actually change.
There was a problem hiding this comment.
Thanks for the heads-up.
I did in fact only change the copyright headers on the files I modified to begin with, but when I was 'polishing it up' to submit as a pull request I went back and added to the other files.
I guess the thought was that the enter module would be subject to copyright rather than each file within it.
No matter, I will change it :)
|
|
||
| @tools.ormcache(skiparg=0) | ||
| def get_session_parameters(self, db): | ||
| def _auth_timeout_get_parameter_delay(self, db): |
There was a problem hiding this comment.
This is changing the public external facing interface of a module that is already in production, and therefore is against a stable release policy.
Is the rename of this method actually necessary? If so, we'll need to provide a get_session_parameters method to use as an adaptation layer for old code.
There was a problem hiding this comment.
I was trying to be granular here.
With the new structure in ResUser each param is required in different places, so I split get_session_parameters in two.
Alternatively I could have just called get_session_parameters in all the now required places, using the parameter returned that I need and discarding the other; however I was feeling the need to be frugal given that from what I can see these methods are running in a fairly hot code-path.
The other thing that occurs to me now is that this code now opens more cursors than before.
Technically this new code would open and close a cursor for each parameter read, whereas they were both read in a single cursor before.
Am I barking up the wrong tree here?
Should I be being less frugal and instead trust the ORM layer to mitigate any repeat work ?
There was a problem hiding this comment.
I 100% agree with your design choice. The solution here is to basically just create a get_session_parameters method that returns the output of the two new methods in a compatible tuple
EDIT: I'll comment inline about the cursors
| finally: | ||
| cr.close() | ||
| return delay, urls | ||
| return urls |
There was a problem hiding this comment.
This is changing the external facing API. The adapter method would need to return compatibly
| self.get_session_parameters.clear_cache(self) | ||
| if self.key == DELAY_KEY: | ||
| self._auth_timeout_get_parameter_delay.clear_cache(self) | ||
| if self.key == IGNORED_PATH_KEY: |
| _inherit = 'res.users' | ||
|
|
||
| def _check_session_validity(self, db, uid, passwd): | ||
| def _auth_timeout_urls_get(self, session, db, uid): |
There was a problem hiding this comment.
It could be argued that you are also changing the interfaces here, but they are private so you're somewhat in the clear. I would still recommend an adapter method though- you don't want to be the reason that someone's code breaks in production.
|
|
||
| def _check_session_validity(self, db, uid, passwd): | ||
| def _auth_timeout_urls_get(self, session, db, uid): | ||
| # Pluggable method for calculating ignored urls |
There was a problem hiding this comment.
Check out PEP-257, which describes Pythonic docblocks. This is more akin to a C docblock
| def _auth_timeout_urls_get(self, session, db, uid): | ||
| # Pluggable method for calculating ignored urls | ||
| # Defaults to stored config param | ||
| param_obj = self.pool['ir.config_parameter'] |
There was a problem hiding this comment.
self.env - Pool is old API. Please don't use
There was a problem hiding this comment.
FYI, self.env is not defined in these methods.
Was able to use request.env, but I'd rather find out why self.env isn't working.
| def _auth_timeout_deadline_calculate(self, session, db, uid): | ||
| # Pluggable method for calculating timeout deadline | ||
| # Defaults to current time minus delay using delay stored as session param | ||
| param_obj = self.pool['ir.config_parameter'] |
| try: | ||
| expired = getmtime(path) < deadline | ||
| except OSError: | ||
| pass |
There was a problem hiding this comment.
Never pass silently. Please add a _logger.debug here at minimum
| except OSError: | ||
| pass | ||
| except OSError: | ||
| pass |
There was a problem hiding this comment.
I know it's not your code, but you're already here & changing things. Never pass silently - _logger.debug
|
@lasley Thanks for the input. Will investigate changes required! |
| def get_session_parameters(self, db): | ||
| def _auth_timeout_get_parameter_delay(self, db): | ||
| param_model = self.pool['ir.config_parameter'] | ||
| cr = self.pool.cursor() |
There was a problem hiding this comment.
Sounds like you're going for a real fix, I ❤️ it and thank you! Let's do like this in both of the cursor areas:
with openerp.registry(self.env.cr.dbname).cursor() as cr:
...operations...
This will kill the try/finally.
Now, I do have a question regarding this & forgive if it's basic - I don't know this module. Why are we opening new cursors in these spots?
There was a problem hiding this comment.
I wasn't sure why this was done originally, so followed the pattern in case it had good reason.
This is all complete conjecture, but:
Seems to me that the ResUser.check method could quite likely be called on requests that are at a stage that have not had their proper environment/context set up yet as part of request buildup/teardown.
I.e. Odoo should check a users validation credentials before opening them an active db cursor, etc.
Since this module hangs off ResUser.check, we get caught in that scenario.
The only scenario we are actually interested in though is (re)checks - we don't need to check for session expiry on the request that is logging a user into the system (but we do)
It would not surprise me if the manual cursor control was added as a workaround by the original developer(s) as they quickly realized that without them users could no longer log in!
There was a problem hiding this comment.
I have taken the manual cursors out for now, and everything still appears to work correctly.
In order to use a manual cursor with the newer API, I will have to create a new env instance, from what I can see.
|
Man, minimum line width of 79 in conjunction with strict line-continuation indent rules presents an interesting challenge. |
| """ | ||
| param_model = self.env['ir.config_parameter'] | ||
| delay = int(param_model.sudo().get_param(DELAY_KEY, 7200)) | ||
| urls = param_model.sudo().get_param(IGNORED_PATH_KEY, '').split(',') |
There was a problem hiding this comment.
Method no longer using the passed in db for database access
| @tools.ormcache('db') | ||
| def get_session_parameters(self, db): | ||
| param_model = self.pool['ir.config_parameter'] | ||
| cr = self.pool.cursor() |
There was a problem hiding this comment.
self.pool usage: reasoning listed in separate comment
|
|
||
| def _auth_timeout_get_parameter_delay(self): | ||
| delay, urls = self.get_session_parameters(self.pool.db_name) | ||
| return delay |
There was a problem hiding this comment.
self.pool usage: reasoning listed in separate comment
|
|
||
| def _auth_timeout_get_parameter_ignoredurls(self): | ||
| delay, urls = self.get_session_parameters(self.pool.db_name) | ||
| return urls |
There was a problem hiding this comment.
self.pool usage: reasoning listed in separate comment
| """Pluggable method for calculating ignored urls | ||
| Defaults to stored config param | ||
| """ | ||
| param_model = self.pool['ir.config_parameter'] |
There was a problem hiding this comment.
self.pool usage: reasoning listed in separate comment
| """Pluggable method for calculating timeout deadline | ||
| Defaults to current time minus delay using delay stored as config param | ||
| """ | ||
| param_model = self.pool['ir.config_parameter'] |
There was a problem hiding this comment.
self.pool usage: reasoning listed in separate comment
| return True | ||
|
|
||
| def _auth_timeout_request_get(self): | ||
| return request |
There was a problem hiding this comment.
See separate comment on tests/mocking
| return request | ||
|
|
||
| def _auth_timeout_session_filename_get(self, sid): | ||
| return root.session_store.get_session_filename(sid) |
There was a problem hiding this comment.
See separate comment on tests/mocking
| return root.session_store.get_session_filename(sid) | ||
|
|
||
| def _auth_timeout_utime(self, path, dates=None): | ||
| return utime(path, dates) |
There was a problem hiding this comment.
See separate comment on tests/mocking
| return utime(path, dates) | ||
|
|
||
| def _auth_timeout_getmtime(self, path): | ||
| return getmtime(path) |
There was a problem hiding this comment.
See separate comment on tests/mocking
| except OSError as e: | ||
| _logger.warning( | ||
| 'Exception reading session file modified time: %s' | ||
| % e |
There was a problem hiding this comment.
I am using warning for these log entries.
Any reason I should use debug instead?
|
Hey @jmorgannz, Appreciation of efforts, |
|
facepalm |
|
|
||
| 'author': "ACSONE SA/NV, Dhinesh D, Odoo Community Association (OCA)", | ||
| 'author': "ACSONE SA/NV, Dhinesh D, Jesse Morgan, \ | ||
| Odoo Community Association (OCA)", |
There was a problem hiding this comment.
Used an escaped newline to fix issue with new author string length.
Mangles the file layout somewhat.
Wasn't sure if un-escaped newlines using """ would do funny things in the author string.
There was a problem hiding this comment.
If you don't like escaped new lines, you can also use multiple strings, like this:
'author': 'ACSONE SA/NV, Dhinesh D, Jesse Morgan, '
'Odoo Community Association (OCA)',
There was a problem hiding this comment.
This is my preferred, although IMO it looks nicer one per line:
'author': 'ACSONE SA/NV, '
'Dhinesh D, '
'Jesse Morgan, '
'Odoo Community Association (OCA)',
|
@jmorgannz - take a look here for local lint |
|
@lasley - thanks - I just hadn't got around to it. I've done it now. |
|
Hi all, |
chienandalu
left a comment
There was a problem hiding this comment.
Thanks @jmorgannz for the good job. I borrowed some ideas for v10 migration indeed 🙂 Some comments below:
|
|
||
| @tools.ormcache(skiparg=0) | ||
| @tools.ormcache('db') | ||
| def get_session_parameters(self, db): |
There was a problem hiding this comment.
I followed @yajo's advice here (#875 (comment)) and got rid of this whole file in favour of new api and method improvements (wich seem to be available in v9 as well: https://github.com/odoo/odoo/blob/9.0/openerp/addons/base/ir/ir_config_parameter.py#L57).
There was a problem hiding this comment.
@chienandalu
Glad you found my changes useful :)
Yes I struggled with the same thoughts myself - at first I couldn't see any reason why changes were required at all in ir_config_parameter.
The best I could come up with is that the original writer wanted to read both and cache once, rather than read twice and cache twice.
In any event it is indeed redundant, although I was advised against removing get_session_parameters (deceptively named for a public method :/) as its in the wild now and might be referenced by some unknown modules.
|
Ok before we continue with the v10, let's knock this one. @chienandalu - have your comments been attended to here? |
|
@lasley Yes, sure 🙂 |
|
Thanks @jmorgannz - congrats on your first OCA submission🥇 ! Look forward to seeing you around 🚀 |
MiquelRForgeFlow
left a comment
There was a problem hiding this comment.
Line https://github.com/OCA/server-tools/pull/887/files#diff-42f066551d06ff9ed8b4c8c7fdc6c8f1R18 should have been changed to 9.0.1.0.1 or 9.0.1.1.0 or 9.0.2.0.0.
|
@lasley Thanks for the help! |
* Module auth_session_timeout: --------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false) * WIP * Fixed flake8 lint errors * Fixed flake8 lint errors * WIP * WIP * WIP * WIP * WIP * WIP * Module: auth-session-timeout: Refactor ResUser tests to use `unittest.mock` patching * Module: auth_session_timeout: Fixed flake8 lint errors * Module: auth_session_timeout: Fixed flake8 lint errors
* Module auth_session_timeout: --------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false) * WIP * Fixed flake8 lint errors * Fixed flake8 lint errors * WIP * WIP * WIP * WIP * WIP * WIP * Module: auth-session-timeout: Refactor ResUser tests to use `unittest.mock` patching * Module: auth_session_timeout: Fixed flake8 lint errors * Module: auth_session_timeout: Fixed flake8 lint errors
* Module auth_session_timeout: --------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false) * WIP * Fixed flake8 lint errors * Fixed flake8 lint errors * WIP * WIP * WIP * WIP * WIP * WIP * Module: auth-session-timeout: Refactor ResUser tests to use `unittest.mock` patching * Module: auth_session_timeout: Fixed flake8 lint errors * Module: auth_session_timeout: Fixed flake8 lint errors
* Module auth_session_timeout: --------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false) * WIP * Fixed flake8 lint errors * Fixed flake8 lint errors * WIP * WIP * WIP * WIP * WIP * WIP * Module: auth-session-timeout: Refactor ResUser tests to use `unittest.mock` patching * Module: auth_session_timeout: Fixed flake8 lint errors * Module: auth_session_timeout: Fixed flake8 lint errors
* Module auth_session_timeout: --------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false) * WIP * Fixed flake8 lint errors * Fixed flake8 lint errors * WIP * WIP * WIP * WIP * WIP * WIP * Module: auth-session-timeout: Refactor ResUser tests to use `unittest.mock` patching * Module: auth_session_timeout: Fixed flake8 lint errors * Module: auth_session_timeout: Fixed flake8 lint errors
* Module auth_session_timeout: --------------------------- * Refactor to allow other modules to inherit and augment or override the following: ** Session expiry time (deadline) calculation ** Ignored URLs ** Final session expiry (with possibility to late-abort) * Re-ordered functionality to remove unnecessary work, as this code is called very often. * Do not expire a session if delay gets set to zero (or unset / false) * WIP * Fixed flake8 lint errors * Fixed flake8 lint errors * WIP * WIP * WIP * WIP * WIP * WIP * Module: auth-session-timeout: Refactor ResUser tests to use `unittest.mock` patching * Module: auth_session_timeout: Fixed flake8 lint errors * Module: auth_session_timeout: Fixed flake8 lint errors
Syncing from upstream OCA/server-tools (14.0)
