From 36d96d484ed8dc3370c2dab9b50b714af702a2c4 Mon Sep 17 00:00:00 2001 From: shortcutme Date: Sun, 3 May 2020 03:59:09 +0200 Subject: [PATCH] Workaround for UiPassword cookie issues with sandboxed iframes --- .../disabled-UiPassword/UiPasswordPlugin.py | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/plugins/disabled-UiPassword/UiPasswordPlugin.py b/plugins/disabled-UiPassword/UiPasswordPlugin.py index bbc2df85..812c188b 100644 --- a/plugins/disabled-UiPassword/UiPasswordPlugin.py +++ b/plugins/disabled-UiPassword/UiPasswordPlugin.py @@ -14,6 +14,7 @@ plugin_dir = os.path.dirname(__file__) if "sessions" not in locals().keys(): # To keep sessions between module reloads sessions = {} + whitelisted_client_ids = {} def showPasswordAdvice(password): @@ -28,8 +29,26 @@ def showPasswordAdvice(password): @PluginManager.registerTo("UiRequest") class UiRequestPlugin(object): sessions = sessions + whitelisted_client_ids = whitelisted_client_ids last_cleanup = time.time() + def getClientId(self): + return self.env["REMOTE_ADDR"] + " - " + self.env["HTTP_USER_AGENT"] + + def whitelistClientId(self, session_id=None): + if not session_id: + session_id = self.getCookies().get("session_id") + client_id = self.getClientId() + if client_id in self.whitelisted_client_ids: + self.whitelisted_client_ids[client_id]["updated"] = time.time() + return False + + self.whitelisted_client_ids[client_id] = { + "added": time.time(), + "updated": time.time(), + "session_id": session_id + } + def route(self, path): # Restict Ui access by ip if config.ui_restrict and self.env['REMOTE_ADDR'] not in config.ui_restrict: @@ -42,10 +61,22 @@ class UiRequestPlugin(object): self.cleanup() # Validate session session_id = self.getCookies().get("session_id") - if session_id not in self.sessions: # Invalid session id, display login + if session_id not in self.sessions and self.getClientId() not in self.whitelisted_client_ids: + # Invalid session id and not whitelisted ip: display login return self.actionLogin() return super(UiRequestPlugin, self).route(path) + def actionWrapper(self, path, *args, **kwargs): + if config.ui_password and self.isWrapperNecessary(path): + session_id = self.getCookies().get("session_id") + if session_id not in self.sessions: + # We only accept cookie based auth on wrapper + return self.actionLogin() + else: + self.whitelistClientId() + + return super().actionWrapper(path, *args, **kwargs) + # Action: Login @helper.encodeResponse def actionLogin(self): @@ -53,13 +84,14 @@ class UiRequestPlugin(object): self.sendHeader() posted = self.getPosted() if posted: # Validate http posted data - if self.checkPassword(posted.get("password")): + if self.sessionCheckPassword(posted.get("password")): # Valid password, create session session_id = self.randomString(26) self.sessions[session_id] = { "added": time.time(), "keep": posted.get("keep") } + self.whitelistClientId(session_id) # Redirect to homepage or referer url = self.env.get("HTTP_REFERER", "") @@ -74,20 +106,26 @@ class UiRequestPlugin(object): template = template.replace("{result}", "bad_password") yield template - def checkPassword(self, password): - return password == config.ui_password - def randomString(self, nchars): return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(nchars)) - @classmethod - def cleanup(cls): - cls.last_cleanup = time.time() - for session_id, session in list(cls.sessions.items()): + def sessionCheckPassword(self, password): + return password == config.ui_password + + def sessionDelete(self, session_id): + del self.sessions[session_id] + + for client_id in list(self.whitelisted_client_ids): + if self.whitelisted_client_ids[client_id]["session_id"] == session_id: + del self.whitelisted_client_ids[client_id] + + def sessionCleanup(self): + self.last_cleanup = time.time() + for session_id, session in list(self.sessions.items()): if session["keep"] and time.time() - session["added"] > 60 * 60 * 24 * 60: # Max 60days for keep sessions - del(cls.sessions[session_id]) + self.sessionDelete(session_id) elif not session["keep"] and time.time() - session["added"] > 60 * 60 * 24: # Max 24h for non-keep sessions - del(cls.sessions[session_id]) + self.sessionDelete(session_id) # Action: Display sessions @helper.encodeResponse @@ -95,6 +133,8 @@ class UiRequestPlugin(object): self.sendHeader() yield "
"
         yield json.dumps(self.sessions, indent=4)
+        yield "\r\n"
+        yield json.dumps(self.whitelisted_client_ids, indent=4)
 
     # Action: Logout
     @helper.encodeResponse
@@ -103,7 +143,8 @@ class UiRequestPlugin(object):
         session_id = self.getCookies().get("session_id")
         if not self.env.get("HTTP_REFERER") or session_id == self.get.get("session_id"):
             if session_id in self.sessions:
-                del self.sessions[session_id]
+                self.sessionDelete(session_id)
+
             self.start_response('301 Redirect', [
                 ('Location', "/"),
                 ('Set-Cookie', "session_id=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT")