Commit 5eb36066 authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

ERP5Security: JWT and DumbExtractor support reset and update Credentials

parent 02fb5fe7
......@@ -27,6 +27,8 @@
#
##############################################################################
from base64 import standard_b64encode
from Products.ERP5Type.Globals import InitializeClass
from AccessControl import ClassSecurityInfo
......@@ -51,12 +53,52 @@ class ERP5DumbHTTPExtractionPlugin(BasePlugin):
#Register value
self._setId(id)
self.title = title
self.cookie_name = "__ac"
security.declarePrivate('extractCredentials')
@UnrestrictedMethod
def extractCredentials(self, request):
return DumbHTTPExtractor().extractCredentials(request);
################################
# ICredentialsUpdatePlugin #
################################
security.declarePrivate('updateCredentials')
def updateCredentials(self, request, response, login, password):
""" Respond to change of credentials"""
kw = {}
portal = self.getPortalObject()
expire_interval = portal.portal_preferences.getPreferredMaxUserInactivityDuration()
if expire_interval in ('', None):
ac_renew = float('inf')
else:
expire_interval /= 86400. # seconds -> days
now = DateTime()
kw['expires'] = (now + expire_interval).toZone('GMT').rfc822()
ac_renew = (now + expire_interval / 2).millis()
portal.portal_sessions[
portal.Base_getAutoLogoutSessionKey(username=login)
]['ac_renew'] = ac_renew
response.setCookie(
name="__ac",
value=standard_b64encode('%s:%s' % (login, password)),
path='/',
secure=getattr(portal, 'REQUEST', {}).get('SERVER_URL', '').startswith('https:'),
http_only=True,
**kw
)
################################
# ICredentialsResetPlugin #
################################
security.declarePrivate( 'resetCredentials' )
def resetCredentials( self, request, response ):
""" Logout
"""
response.expireCookie("__ac", path="/")
#Form for new plugin in ZMI
manage_addERP5DumbHTTPExtractionPluginForm = PageTemplateFile(
'www/ERP5Security_addERP5DumbHTTPExtractionPlugin', globals(),
......@@ -77,6 +119,8 @@ def addERP5DumbHTTPExtractionPlugin(dispatcher, id, title=None, REQUEST=None):
#List implementation of class
classImplements(ERP5DumbHTTPExtractionPlugin,
plugins.ILoginPasswordHostExtractionPlugin
plugins.ILoginPasswordHostExtractionPlugin,
plugins.ICredentialsResetPlugin,
plugins.ICredentialsUpdatePlugin,
)
InitializeClass(ERP5DumbHTTPExtractionPlugin)
......@@ -37,7 +37,7 @@ from AccessControl import ClassSecurityInfo
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PluggableAuthService.interfaces import plugins
from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from Products.ERP5Security.ERP5UserManager import ERP5UserManager
from Products.ERP5Security.ERP5UserManager import getUserByLogin
from Products.PluggableAuthService.permissions import ManageUsers
from Products.PluggableAuthService.PluggableAuthService import DumbHTTPExtractor
from ZODB.utils import u64
......@@ -69,8 +69,10 @@ def addERP5JSONWebTokenPlugin(dispatcher, id, title=None, REQUEST=None):
@implementer(
plugins.ILoginPasswordHostExtractionPlugin,
plugins.ICredentialsResetPlugin,
plugins.ICredentialsUpdatePlugin,
)
class ERP5JSONWebTokenPlugin(ERP5UserManager):
class ERP5JSONWebTokenPlugin(BasePlugin):
meta_type = "ERP5 JSON Web Token Plugin"
security = ClassSecurityInfo()
......@@ -88,7 +90,6 @@ class ERP5JSONWebTokenPlugin(ERP5UserManager):
def __init__(self, *args, **kw):
super(ERP5JSONWebTokenPlugin, self).__init__(*args, **kw)
self.manage_updateERP5JSONWebTokenPlugin()
self.manage_setERP5JSONWebTokenPluginExtpirationDelay(0)
......@@ -138,8 +139,7 @@ class ERP5JSONWebTokenPlugin(ERP5UserManager):
jwt.InvalidTokenError,
jwt.DecodeError,
):
request.response.expireCookie(self.same_site_cookie, path='/')
request.response.expireCookie(self.cors_cookie, path='/')
self.resetCredentials(request, request.response)
return None
person_relative_url = data["sub"].encode()
......@@ -159,25 +159,23 @@ class ERP5JSONWebTokenPlugin(ERP5UserManager):
creds['remote_address'] = request.get('REMOTE_ADDR', '')
return creds
#
# IAuthenticationPlugin implementation
#
security.declarePrivate( 'authenticateCredentials' )
def authenticateCredentials(self, credentials):
authentication_result = super(
ERP5JSONWebTokenPlugin,
self
).authenticateCredentials(credentials)
# In case the password is present in the request, the token is updated
if authentication_result is not None and "password" in credentials:
################################
# ICredentialsUpdatePlugin #
################################
security.declarePrivate('updateCredentials')
def updateCredentials(self, request, response, login, new_password):
""" Respond to change of credentials"""
#Update credential for key auth or standard of.
#Remove conflict between both systems
if login is not None:
if jwt is None:
LOG('ERP5JSONWebTokenPlugin', INFO,
'No jwt module, install pyjwt package. '
'Authentication disabled.')
return authentication_result
user = self.getUserByLogin(authentication_result[0])[0]
user = getUserByLogin(self.getPortalObject(), login)[0]
# Activate password to have the real tid
user.password._p_activate()
......@@ -221,17 +219,24 @@ class ERP5JSONWebTokenPlugin(ERP5UserManager):
cookie = self.same_site_cookie
cookie_parameters["same_site"] = "Lax"
request.response.setCookie(
response.setCookie(
cookie,
jwt.encode(data, self._secret),
**cookie_parameters
)
# Expire default cookie set by default
# (even with plugin deactivated)
# request.response.expireCookie('__ac')
return authentication_result
################################
# ICredentialsResetPlugin #
################################
security.declarePrivate( 'resetCredentials' )
def resetCredentials( self, request, response ):
""" Logout
"""
for cookie in (self.same_site_cookie,
self.cors_cookie):
if request.cookies.get(cookie) is not None:
response.expireCookie(cookie, path="/")
################################
# Properties for ZMI managment #
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment