[gen] Bug and performance fixes in the authentication mechanism.

This commit is contained in:
Gaetan Delannay 2015-01-26 14:10:50 +01:00
parent 0961dc591f
commit 73f81d9304
4 changed files with 34 additions and 15 deletions

View file

@ -226,9 +226,15 @@ class Ref(Field):
</div>
</div>''')
# PX that displays referred objects as a list.
pxToggleIcon = Px('''
<img class="clickable" onclick="toggleCookie('appyHistory')"
src=":True and url('collapse.gif') or url('expand.gif')"
align=":dleft" id="appyHistory_img" style="padding-right:4px"/>''')
# PX that displays referred objects as a list
pxViewList = Px('''
<div if="not innerRef or mayAdd or mayLink" style="margin-bottom: 4px">
<x if="field.collapsible">:field.pxToggleIcon</x>
<span if="subLabel" class="discreet">:_(subLabel)</span>
(<span class="discreet">:totalNumber</span>)
<x>:field.pxAdd</x>
@ -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,

View file

@ -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:

View file

@ -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 }

View file

@ -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':