From 73f81d9304910e8ef24445bbf34cd6066453b809 Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Mon, 26 Jan 2015 14:10:50 +0100 Subject: [PATCH] [gen] Bug and performance fixes in the authentication mechanism. --- fields/ref.py | 13 +++++++++++-- gen/mixins/ToolMixin.py | 14 +++++++++++--- gen/ui/appy.css | 13 +++++++------ gen/wrappers/UserWrapper.py | 9 +++++---- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/fields/ref.py b/fields/ref.py index 5318d94..289a626 100644 --- a/fields/ref.py +++ b/fields/ref.py @@ -226,9 +226,15 @@ class Ref(Field): ''') - # PX that displays referred objects as a list. + pxToggleIcon = Px(''' + ''') + + # PX that displays referred objects as a list pxViewList = Px('''
+ :field.pxToggleIcon :_(subLabel) (:totalNumber) :field.pxAdd @@ -533,7 +539,7 @@ class Ref(Field): scolspan=1, swidth=None, sheight=None, sselect=None, persist=True, render='list', menuIdMethod=None, menuInfoMethod=None, menuUrlMethod=None, view=None, xml=None, - showActions=True): + showActions=True, collapsible=False): self.klass = klass self.attribute = attribute # May the user add new objects through this ref ? "add" may also contain @@ -720,6 +726,9 @@ class Ref(Field): # appear in a "div" tag, below the object title; if "inline", they will # appear besides it, producing a more compact list of results. self.showActions = showActions + # If "collapsible" is True, a "+/-" icon will allow to expand/collapse + # the tied or available objects. + self.collapsible = collapsible if showActions == True: self.showActions = 'block' # Call the base constructor Field.__init__(self, validator, multiplicity, default, show, page, diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py index e776a83..65c24b2 100644 --- a/gen/mixins/ToolMixin.py +++ b/gen/mixins/ToolMixin.py @@ -927,8 +927,10 @@ class ToolMixin(BaseMixin): cfg = self.getProductConfig(True).ldap if cfg: user = cfg.getUser(self.appy(), login, password) elif source == 'any': - # Get the user object, be it really local or a copy of a LDAP user - user = self.getUser(source='zodb') or self.getUser(source='ldap') + # Get the User object, be it really local or representing an + # external user. This way, we avoid contacting the distant source + # every time authentification is required. + user = tool.search1('User', noSecurity=True, login=login) if not user: return # Authentify the user if required if authentify: @@ -943,6 +945,7 @@ class ToolMixin(BaseMixin): gutils.writeCookie(login, password, req) # Cache the user and some precomputed values, for performance req.user = user + req.userLogin = user.login req.userRoles = user.getRoles() req.userLogins = user.getLogins() req.zopeUser = user.getZopeUser() @@ -958,7 +961,8 @@ class ToolMixin(BaseMixin): msg = self.translate('enable_cookies') return self.goto(urlBack, msg) # Authenticate the user - if self.getUser(authentify=True, source='any'): + if self.getUser(authentify=True, source='zodb') or \ + self.getUser(authentify=True, source='ldap'): msg = self.translate('login_ok') logMsg = 'logged in.' else: @@ -1015,6 +1019,10 @@ class ToolMixin(BaseMixin): id = a.getId() if id and (os.path.splitext(id)[-1].lower() in tool.staticExtensions): return self._nobody.__of__(self) + # Skip authorization when the performing http login: else, it will be + # done twice. + if (id == 'config') and (v.__name__ == 'performLogin'): + return self._nobody.__of__(self) # Identify and authentify the user user = tool.getUser(authentify=True, source='any') if not user: diff --git a/gen/ui/appy.css b/gen/ui/appy.css index db93853..374204b 100644 --- a/gen/ui/appy.css +++ b/gen/ui/appy.css @@ -34,7 +34,7 @@ select { border: 1px solid #d0d0d0; background-color: white } textarea { width: 99%; font: 100% "Lucida Grande","Lucida Sans Unicode",Helvetica,Arial,Verdana,sans-serif; border: 1px solid #d0d0d0; background-color: white } -label { color: #888888; font-size: 11px; margin: 3px 0; +label { color: #555555; font-size: 11px; margin: 3px 0; text-transform: uppercase } legend { padding-bottom: 2px; padding-right: 3px; color: black } ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0; @@ -69,7 +69,8 @@ input.buttonFixed { width:110px; padding: 0 0 0 10px } .xhtml p { margin: 3px 0 7px 0 } .clickable { cursor: pointer } .help { cursor: help } -.refLink { font-style: italic; padding-left: 5px; font-size: 90%; color: grey } +.refLink { font-style: italic; padding-left: 5px; font-size: 90%; + color: #555555 } .buttons { margin-left: 4px } .objectButtons { margin-top: 5px } .message { position: absolute; top: -40px; left: 50%; font-size: 90%; @@ -82,7 +83,7 @@ input.buttonFixed { width:110px; padding: 0 0 0 10px } background-color: #d7dee4; border-radius: 2px 2px 2px 2px; box-shadow: 0 2px 4px #A9A9A9 } .focus td { padding: 4px 0px 4px 4px } -.discreet { font-size: 90%; color: grey } +.discreet { font-size: 90%; color: #555555 } .title {} .lostPassword { font-size: 90%; color: white; padding-left: 1em } .current { font-weight: bold } @@ -115,7 +116,7 @@ td.search { padding-top: 8px } .addFormMenu { display: inline; padding: 0 5px 0 3px } .inline { display: inline } .list { margin-bottom: 3px } -.list td, .list th { border: 3px solid #ededed; color: grey; +.list td, .list th { border: 3px solid #ededed; color: #555555; padding: 3px 5px 3px 5px } .list th { background-color: #e5e5e5; font-style: italic; font-weight: normal } .compact { font-size: 90%; width: 100% } @@ -125,7 +126,7 @@ td.search { padding-top: 8px } .grid td { padding: 3px 3px 0 3px } .msgTable { margin: 6px 0; width: 100%; font-size: 93% } .msgTable tr { vertical-align: top } -.msgTable td, .msgTable th { border: 1px solid grey; color: grey; +.msgTable td, .msgTable th { border: 1px solid grey; color: #555555; padding: 0px 5px; text-align: left } .msgTable th { background-color: #f0e3b8; font-style: italic; font-weight: normal } @@ -184,7 +185,7 @@ td.search { padding-top: 8px } .tabs { position:relative; bottom:-2px } .tab { padding: 0 10px 0 10px; text-align: center; font-size: 90%; font-weight: bold} -.language {color: grey; font-size: 7pt; border: grey 1px solid; padding: 2px; +.language {color: #555555; font-size: 7pt; border: grey 1px solid; padding: 2px; margin: 0 2px 0 4px; font-family: monospace } .highlight { background-color: yellow } .globalActions { margin-bottom: 4px } diff --git a/gen/wrappers/UserWrapper.py b/gen/wrappers/UserWrapper.py index 9c30ed4..6b4254f 100644 --- a/gen/wrappers/UserWrapper.py +++ b/gen/wrappers/UserWrapper.py @@ -121,7 +121,8 @@ class UserWrapper(AbstractWrapper): zopeUser = self.getZopeUser() tool = self.tool.o zopeUser.__ = self.encryptPassword(newPassword) - if self.user and (self.user.login == login): + req = tool.REQUEST + if hasattr(req, 'user') and (req.userLogin == login): # The user for which we change the password is the currently logged # user. So update the authentication cookie, too. gutils.writeCookie(login, newPassword, self.request) @@ -302,7 +303,7 @@ class UserWrapper(AbstractWrapper): # Try first to get those logins from a cache on the request, if this # user corresponds to the logged user. rq = self.request - if (self.user == self) and hasattr(rq, 'userLogins'): + if hasattr(rq, 'userLogins') and (rq.userLogin == self.login): return rq.userLogins # Compute it res = [group.login for group in self.groups] @@ -316,9 +317,9 @@ class UserWrapper(AbstractWrapper): # Try first to get those roles from a cache on the request, if this user # corresponds to the logged user. rq = self.request - if (self.user == self) and hasattr(rq, 'userRoles'): + if hasattr(rq, 'userRoles') and (rq.userLogin == self.login): return rq.userRoles - # Compute it. + # Compute it res = list(self.roles) # Add ungrantable roles if self.o.id == 'anon':