Commit e946827a authored by Cédric Le Ninivin's avatar Cédric Le Ninivin

Cache Cookie Extractor For Oauth 2 Authentication

Conflicts:
	product/ERP5Security/__init__.py
parent a7b2163f
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from zLOG import LOG, WARNING
from Products.ERP5Type.Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PluggableAuthService.interfaces import plugins
from Products.PluggableAuthService.utils import classImplements
from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from .utils import getHostFromRequest
class ERP5CacheCookieCredentialExtractionPlugin(BasePlugin):
"""
Extracts credentials from a ram cache, based on a cookie value received
from request.
"""
security = ClassSecurityInfo()
meta_type = 'ERP5 Cache Cookie Credential Extraction Plugin'
_properties=(
{'id': 'cookie_id', 'type': 'string', 'mode': 'w'},
{'id': 'cache_factory_id', 'type': 'string', 'mode': 'w'},
{'id': 'cache_scope', 'type': 'string', 'mode': 'w'},
)
def __init__(self, id, cookie_id, cache_factory_id, title=None,
cache_scope=None):
self._setId(id)
self.title = title
self.cookie_id = cookie_id
self.cache_factory_id = cache_factory_id
self.cache_scope = cache_scope
security.declarePrivate('extractCredentials')
def extractCredentials(self, request):
try:
cookie = request.cookies[self.cookie_id]
except KeyError:
pass
else:
portal_caches = self.getPortalObject().portal_caches
try:
# TODO: When portal_cache allows accessing factories from persistent
# objects, catch AttributeError instead of KeyError and replace the
# following line with this:
#cache_factory = getattr(portal_caches, self.cache_factory_id)
# XXX: getRamCacheRoot is misnamed: its return value contains all kinds
# of caches, actually.
cache_factory = portal_caches.getRamCacheRoot()[self.cache_factory_id]
except KeyError:
LOG(self.id, WARNING, 'Cache factory not found: %r' % (
self.cache_factory_id, ))
else:
for cache_plugin in cache_factory.getCachePluginList():
cache_entry = cache_plugin.get(cookie, self.cache_scope or
self.cookie_id, None)
if cache_entry is not None:
entry_value = cache_entry.getValue()
try:
login = entry_value['login']
except KeyError:
pass
else:
remote_host, remote_address = getHostFromRequest(request)
return {
'external_login': login,
'remote_host': remote_host,
'remote_address': remote_address,
}
return {}
classImplements(ERP5CacheCookieCredentialExtractionPlugin,
plugins.IExtractionPlugin,
)
InitializeClass(ERP5CacheCookieCredentialExtractionPlugin)
manage_addERP5CacheCookieCredentialExtractionPluginForm = PageTemplateFile(
'www/ERP5Security_addERP5CacheCookieCredentialExtractionPlugin', globals(),
__name__='manage_addERP5CacheCookieCredentialExtractionPluginForm')
def addERP5CacheCookieCredentialExtractionPlugin(dispatcher, id, cookie_id,
cache_scope, cache_factory_id, title=None, REQUEST=None):
""" bla bla, mandatory docstring """
if not cookie_id:
raise ValueError('cookie_id is mandatory')
if not cache_factory_id:
raise ValueError('cache_factory_id is mandatory')
plugin = ERP5CacheCookieCredentialExtractionPlugin(
id=id,
title=title,
cookie_id=cookie_id,
cache_scope=cache_scope,
cache_factory_id=cache_factory_id,
)
dispatcher._setObject(plugin.getId(), plugin)
if REQUEST is not None:
REQUEST['RESPONSE'].redirect(
dispatcher.absolute_url() + '/manage_workspace?manage_tabs_message='
'Add+ERP5+Cache+Cookie+Credential+Extraction+Plugin+added.',
)
...@@ -31,6 +31,7 @@ import ERP5BearerExtractionPlugin ...@@ -31,6 +31,7 @@ import ERP5BearerExtractionPlugin
import ERP5ExternalOauth2ExtractionPlugin import ERP5ExternalOauth2ExtractionPlugin
import ERP5AccessTokenExtractionPlugin import ERP5AccessTokenExtractionPlugin
import ERP5DumbHTTPExtractionPlugin import ERP5DumbHTTPExtractionPlugin
import ERP5CacheCookieCredentialExtractionPlugin
def mergedLocalRoles(object): def mergedLocalRoles(object):
"""Returns a merging of object and its ancestors' """Returns a merging of object and its ancestors'
...@@ -71,6 +72,7 @@ registerMultiPlugin(ERP5ExternalOauth2ExtractionPlugin.ERP5FacebookExtractionPlu ...@@ -71,6 +72,7 @@ registerMultiPlugin(ERP5ExternalOauth2ExtractionPlugin.ERP5FacebookExtractionPlu
registerMultiPlugin(ERP5ExternalOauth2ExtractionPlugin.ERP5GoogleExtractionPlugin.meta_type) registerMultiPlugin(ERP5ExternalOauth2ExtractionPlugin.ERP5GoogleExtractionPlugin.meta_type)
registerMultiPlugin(ERP5AccessTokenExtractionPlugin.ERP5AccessTokenExtractionPlugin.meta_type) registerMultiPlugin(ERP5AccessTokenExtractionPlugin.ERP5AccessTokenExtractionPlugin.meta_type)
registerMultiPlugin(ERP5DumbHTTPExtractionPlugin.ERP5DumbHTTPExtractionPlugin.meta_type) registerMultiPlugin(ERP5DumbHTTPExtractionPlugin.ERP5DumbHTTPExtractionPlugin.meta_type)
registerMultiPlugin(ERP5CacheCookieCredentialExtractionPlugin.ERP5CacheCookieCredentialExtractionPlugin.meta_type)
def initialize(context): def initialize(context):
...@@ -173,6 +175,15 @@ def initialize(context): ...@@ -173,6 +175,15 @@ def initialize(context):
, icon='www/portal.gif' , icon='www/portal.gif'
) )
context.registerClass( ERP5CacheCookieCredentialExtractionPlugin.ERP5CacheCookieCredentialExtractionPlugin
, permission=ManageUsers
, constructors=(
ERP5CacheCookieCredentialExtractionPlugin.manage_addERP5CacheCookieCredentialExtractionPluginForm,
ERP5CacheCookieCredentialExtractionPlugin.addERP5CacheCookieCredentialExtractionPlugin, )
, visibility=None
, icon='www/portal.gif'
)
from AccessControl.SecurityInfo import ModuleSecurityInfo from AccessControl.SecurityInfo import ModuleSecurityInfo
ModuleSecurityInfo('Products.ERP5Security.ERP5UserManager').declarePublic( ModuleSecurityInfo('Products.ERP5Security.ERP5UserManager').declarePublic(
'getUserByLogin') 'getUserByLogin')
##############################################################################
#
# Copyright (c) 2012 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
def getHostFromRequest(request):
try:
remote_address = request.getClientAddr()
except AttributeError:
remote_address = request.get('REMOTE_ADDR', '')
return (request.get('REMOTE_HOST', ''), remote_address)
<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1>
<h2 tal:define="form_title string:Add Cache Cookie Credential Extraction Plugin"
tal:replace="structure context/manage_form_title">FORM TITLE</h2>
<p class="form-help">Please input the configuration</p>
<form action="addERP5CacheCookieCredentialExtractionPlugin" method="POST">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top"><div class="form-label">Id</div></td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top"><div class="form-label">Title</div></td>
<td align="left" valign="top">
<input type="text" name="title" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top"><div class="form-label">Cookie ID</div></td>
<td align="left" valign="top">
<input type="text" name="cookie_id" size="40" value="__ac_CHANGE_ME" />
</td>
</tr>
<tr>
<td align="left" valign="top"><div class="form-label">Cache scope (if left empty, becomes Cookie ID)</div></td>
<td align="left" valign="top">
<input type="text" name="cache_scope" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top"><div class="form-label">Cache factory</div></td>
<td align="left" valign="top">
<input type="text" name="cache_factory_id" size="40" value="credential_cache_factory" />
</td>
</tr>
<tr><td colspan="2"><input type="submit" value="add plugin"/></td></tr>
</table>
</form>
<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1>
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