Hi Dave,

Please find attached patch (old RM2713).
Also for server group and server module login required checks were missing,
I have added them in same patch

-- 
*Harshal Dhumal*
*Sr. Software Engineer*

EnterpriseDB India: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

On Tue, Oct 10, 2017 at 11:39 AM, Harshal Dhumal <
harshal.dhu...@enterprisedb.com> wrote:

> Hi David,
>
> Thanks for you input. Session was not invalidated (otherwise execution
> would not have reached to connection manager); Only value of '_id' was
> changed for session.
>
> If we look at code
> <https://github.com/maxcountryman/flask-login/blob/master/flask_login/utils.py#L333>
> how '_id' is generated then we can see it uses remote address and user-agent
> to generate it. I thing we should use another session identifier (sid -
> session id) to map user connection from connection manager.
>
> --
> *Harshal Dhumal*
> *Sr. Software Engineer*
>
> EnterpriseDB India: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
> On Mon, Oct 9, 2017 at 10:18 PM, David Gilman <davidgilm...@gmail.com>
> wrote:
>
>> You can probably stand down on this one. The issue was that my PC was
>> switching back and forth between IPv4 and IPv6 for whatever reason and when
>> that happened the cookie and my session would get invalidated. Maybe it is
>> worth making code changes so you don't get Python tracebacks dumped to the
>> error logs every time this happens but I have been able to resolve the
>> issue by turning off IPv6 temporarily. That was an interesting one to
>> troubleshoot!
>>
>> On Mon, Oct 9, 2017 at 4:30 AM, Harshal Dhumal <
>> harshal.dhu...@enterprisedb.com> wrote:
>>
>>> sure Dave
>>>
>>> --
>>> *Harshal Dhumal*
>>> *Sr. Software Engineer*
>>>
>>> EnterpriseDB India: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>> On Mon, Oct 9, 2017 at 1:16 PM, Dave Page <dp...@pgadmin.org> wrote:
>>>
>>>> Harshal, can you help with this please?
>>>>
>>>> On Sun, Oct 8, 2017 at 12:39 AM, David Gilman <davidgilm...@gmail.com>
>>>> wrote:
>>>>
>>>>> I'm trying out pgadmin4 v2.0 for the first time.  It seems that after
>>>>> only a few minutes (maybe even less than five) my pgadmin4 session will 
>>>>> get
>>>>> logged out and I'll need to log in again and reopen everything from
>>>>> scratch.  This exception is thrown in the mod_wsgi logs:
>>>>>
>>>>> mod_wsgi (pid=5965): Exception occurred processing WSGI script
>>>>> '/home/pgadmin/venv/lib/python2.7/site-packages/pgadmin4/pgA
>>>>> dmin4.wsgi'.
>>>>> Traceback (most recent call last):
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 2000, in __call__
>>>>>     return self.wsgi_app(environ, start_response)
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1991, in wsgi_app
>>>>>     response = self.make_response(self.handle_exception(e))
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1567, in handle_exception
>>>>>     reraise(exc_type, exc_value, tb)
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1988, in wsgi_app
>>>>>     response = self.full_dispatch_request()
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1641, in full_dispatch_request
>>>>>     rv = self.handle_user_exception(e)
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1544, in handle_user_exception
>>>>>     reraise(exc_type, exc_value, tb)
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1639, in full_dispatch_request
>>>>>     rv = self.dispatch_request()
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask/app.py",
>>>>> line 1625, in dispatch_request
>>>>>     return self.view_functions[rule.endpoint](**req.view_args)
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/flask_login.py",
>>>>> line 792, in decorated_view
>>>>>     return func(*args, **kwargs)
>>>>>   File 
>>>>> "/home/pgadmin/venv/lib/python2.7/site-packages/pgadmin4/pgadmin/dashboard/__init__.py",
>>>>> line 169, in wrap
>>>>>     kwargs['sid']
>>>>>   File "/home/pgadmin/venv/lib/python2.7/site-packages/pgadmin4/pga
>>>>> dmin/utils/driver/psycopg2/__init__.py", line 2000, in
>>>>> connection_manager
>>>>>     if session['_id'] not in self.managers:
>>>>>   File 
>>>>> "/home/pgadmin/venv/local/lib/python2.7/site-packages/werkzeug/local.py",
>>>>> line 368, in <lambda>
>>>>>     __getitem__ = lambda x, i: x._get_current_object()[i]
>>>>> KeyError: '_id'
>>>>>
>>>>> My setup:
>>>>> pgadmin4 v2.0 .  The configuration is all defaults except
>>>>> for LOG_FILE/SQLITE_PATH/SESSION_DB_PATH/STORAGE_DIR.  That
>>>>> means MAX_SESSION_IDLE_TIME is at its default of 60 (minutes).
>>>>> pgadmin4 is in server mode with mod_wsgi as a host.
>>>>> PostgreSQL 9.4.14 - from the postgres apt repository.  No changes made
>>>>> to timeouts or anything in the postgresql.conf , it's all defaults.
>>>>> Python 2.7
>>>>> psycopg2 2.7.3.1
>>>>>
>>>>> I can confirm that the apache process hosting pgadmin4 is running
>>>>> under the right UNIX user account and that it seems to have good
>>>>> access/permissions to its scratch files on disk.  I see updates being made
>>>>> to pgadmin4.db and the sessions directory.
>>>>>
>>>>> --
>>>>> David Gilman
>>>>> :DG<
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EnterpriseDB UK: http://www.enterprisedb.com
>>>> The Enterprise PostgreSQL Company
>>>>
>>>
>>>
>>
>>
>> --
>> David Gilman
>> :DG<
>>
>
>
diff --git a/web/pgadmin/browser/server_groups/__init__.py b/web/pgadmin/browser/server_groups/__init__.py
index fd2b4ac..a45d4d7 100644
--- a/web/pgadmin/browser/server_groups/__init__.py
+++ b/web/pgadmin/browser/server_groups/__init__.py
@@ -13,9 +13,9 @@ import simplejson as json
 from abc import ABCMeta, abstractmethod
 
 import six
-from flask import request, render_template, make_response, jsonify, current_app
+from flask import request, jsonify
 from flask_babel import gettext
-from flask_security import current_user
+from flask_security import current_user, login_required
 from pgadmin.browser import BrowserPluginModule
 from pgadmin.browser.utils import NodeView
 from pgadmin.utils.ajax import make_json_response, gone, \
@@ -95,6 +95,7 @@ class ServerGroupView(NodeView):
     parent_ids = []
     ids = [{'type': 'int', 'id': 'gid'}]
 
+    @login_required
     def list(self):
         res = []
 
@@ -108,6 +109,7 @@ class ServerGroupView(NodeView):
 
         return ajax_response(response=res, status=200)
 
+    @login_required
     def delete(self, gid):
         """Delete a server group node in the settings database"""
 
@@ -149,6 +151,7 @@ class ServerGroupView(NodeView):
 
         return make_json_response(result=request.form)
 
+    @login_required
     def update(self, gid):
         """Update the server-group properties"""
 
@@ -195,6 +198,7 @@ class ServerGroupView(NodeView):
             )
         )
 
+    @login_required
     def properties(self, gid):
         """Update the server-group properties"""
 
@@ -217,6 +221,7 @@ class ServerGroupView(NodeView):
                 status=200
             )
 
+    @login_required
     def create(self):
         """Creates new server-group """
         data = request.form if request.form else json.loads(
@@ -261,21 +266,27 @@ class ServerGroupView(NodeView):
                 success=0,
                 errormsg=gettext('No server group name was specified'))
 
+    @login_required
     def sql(self, gid):
         return make_json_response(status=422)
 
+    @login_required
     def modified_sql(self, gid):
         return make_json_response(status=422)
 
+    @login_required
     def statistics(self, gid):
         return make_json_response(status=422)
 
+    @login_required
     def dependencies(self, gid):
         return make_json_response(status=422)
 
+    @login_required
     def dependents(self, gid):
         return make_json_response(status=422)
 
+    @login_required
     def nodes(self, gid=None):
         """Return a JSON document listing the server groups for the user"""
         nodes = []
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index bdff7b2..d3342b9 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -13,7 +13,7 @@ import pgadmin.browser.server_groups as sg
 from flask import render_template, request, make_response, jsonify, \
     current_app, url_for
 from flask_babel import gettext
-from flask_security import current_user
+from flask_security import current_user, login_required
 from pgadmin.browser.server_groups.servers.types import ServerType
 from pgadmin.browser.utils import PGChildNodeView
 from pgadmin.utils.ajax import make_json_response, bad_request, forbidden, \
@@ -73,6 +73,7 @@ class ServerModule(sg.ServerGroupPluginModule):
         """
         return sg.ServerGroupModule.NODE_TYPE
 
+    @login_required
     def get_nodes(self, gid):
         """Return a JSON document listing the server groups for the user"""
         servers = Server.query.filter_by(user_id=current_user.id,
@@ -276,6 +277,7 @@ class ServerNode(PGChildNodeView):
 
         return flag, data
 
+    @login_required
     def nodes(self, gid):
         res = []
         """
@@ -324,7 +326,7 @@ class ServerNode(PGChildNodeView):
 
         return make_json_response(result=res)
 
-
+    @login_required
     def node(self, gid, sid):
         """Return a JSON document listing the server groups for the user"""
         server = Server.query.filter_by(user_id=current_user.id,
@@ -371,6 +373,7 @@ class ServerNode(PGChildNodeView):
             )
         )
 
+    @login_required
     def delete(self, gid, sid):
         """Delete a server node in the settings database."""
         servers = Server.query.filter_by(user_id=current_user.id, id=sid)
@@ -401,6 +404,7 @@ class ServerNode(PGChildNodeView):
         return make_json_response(success=1,
                                   info=gettext("Server deleted"))
 
+    @login_required
     def update(self, gid, sid):
         """Update the server settings"""
         server = Server.query.filter_by(
@@ -520,6 +524,7 @@ class ServerNode(PGChildNodeView):
             )
         )
 
+    @login_required
     def list(self, gid):
         """
         Return list of attributes of all servers.
@@ -561,6 +566,7 @@ class ServerNode(PGChildNodeView):
             response=res
         )
 
+    @login_required
     def properties(self, gid, sid):
         """Return list of attributes of a server"""
         server = Server.query.filter_by(
@@ -615,6 +621,7 @@ class ServerNode(PGChildNodeView):
             }
         )
 
+    @login_required
     def create(self, gid):
         """Add a server node to the settings database"""
         required_args = [
@@ -752,12 +759,15 @@ class ServerNode(PGChildNodeView):
                 errormsg=str(e)
             )
 
+    @login_required
     def sql(self, gid, sid):
         return make_json_response(data='')
 
+    @login_required
     def modified_sql(self, gid, sid):
         return make_json_response(data='')
 
+    @login_required
     def statistics(self, gid, sid):
         manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
         conn = manager.connection()
@@ -781,9 +791,11 @@ class ServerNode(PGChildNodeView):
             )
         )
 
+    @login_required
     def dependencies(self, gid, sid):
         return make_json_response(data='')
 
+    @login_required
     def dependents(self, gid, sid):
         return make_json_response(data='')
 
diff --git a/web/pgadmin/dashboard/__init__.py b/web/pgadmin/dashboard/__init__.py
index 2214f53..382245a 100644
--- a/web/pgadmin/dashboard/__init__.py
+++ b/web/pgadmin/dashboard/__init__.py
@@ -8,10 +8,7 @@
 ##########################################################################
 
 """A blueprint module implementing the dashboard frame."""
-MODULE_NAME = 'dashboard'
-
 from functools import wraps
-
 from flask import render_template, url_for, Response, g
 from flask_babel import gettext
 from flask_security import login_required
@@ -25,6 +22,8 @@ from pgadmin.utils.preferences import Preferences
 
 from config import PG_DEFAULT_DRIVER
 
+MODULE_NAME = 'dashboard'
+
 
 class DashboardModule(PgAdminModule):
     def __init__(self, *args, **kwargs):
diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py
index 527e175..6f56765 100644
--- a/web/pgadmin/utils/driver/psycopg2/__init__.py
+++ b/web/pgadmin/utils/driver/psycopg2/__init__.py
@@ -1997,8 +1997,8 @@ class Driver(BaseDriver):
         assert (sid is not None and isinstance(sid, int))
         managers = None
 
-        if session['_id'] not in self.managers:
-            self.managers[session['_id']] = managers = dict()
+        if session.sid not in self.managers:
+            self.managers[session.sid] = managers = dict()
             if '__pgsql_server_managers' in session:
                 session_managers = session['__pgsql_server_managers'].copy()
                 session['__pgsql_server_managers'] = dict()
@@ -2013,7 +2013,7 @@ class Driver(BaseDriver):
                     manager._restore(session_managers[server_id])
                     manager.update_session()
         else:
-            managers = self.managers[session['_id']]
+            managers = self.managers[session.sid]
 
         managers['pinged'] = datetime.datetime.now()
         if str(sid) not in managers:
@@ -2089,9 +2089,9 @@ class Driver(BaseDriver):
         manager = self.connection_manager(sid)
         if manager is not None:
             manager.release()
-        if session['_id'] in self.managers and \
-                str(sid) in self.managers[session['_id']]:
-            del self.managers[session['_id']][str(sid)]
+        if session.sid in self.managers and \
+                str(sid) in self.managers[session.sid]:
+            del self.managers[session.sid][str(sid)]
 
     def gc(self):
         """
@@ -2099,7 +2099,7 @@ class Driver(BaseDriver):
         server for more than config.MAX_SESSION_IDLE_TIME.
         """
 
-        # Mininum session idle is 20 minutes
+        # Minimum session idle is 20 minutes
         max_idle_time = max(config.MAX_SESSION_IDLE_TIME or 60, 20)
         session_idle_timeout = datetime.timedelta(minutes=max_idle_time)
 
@@ -2108,11 +2108,11 @@ class Driver(BaseDriver):
         for sess in self.managers:
             sess_mgr = self.managers[sess]
 
-            if sess == session.get('_id'):
+            if sess == session.sid:
                 sess_mgr['pinged'] = curr_time
                 continue
 
-            if (curr_time - sess_mgr['pinged'] >= session_idle_timeout):
+            if curr_time - sess_mgr['pinged'] >= session_idle_timeout:
                 for mgr in [m for m in sess_mgr if isinstance(m,
                                                               ServerManager)]:
                     mgr.release()

Reply via email to