[Zope3-checkins] CVS: zopeproducts/sqlauth - __init__.py:1.1 configure.zcml:1.1 interfaces.py:1.1
Albertas Agejevas
alga@codeworks.lt
Fri, 18 Jul 2003 09:31:20 -0400
Update of /cvs-repository/zopeproducts/sqlauth
In directory cvs.zope.org:/tmp/cvs-serv24080
Added Files:
__init__.py configure.zcml interfaces.py
Log Message:
An SQL Principal Source for the Pluggable Authentication Service.
Initial checkin.
=== Added File zopeproducts/sqlauth/__init__.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""SQL based principal source for the Pluggable Authentication Service.
$Id: __init__.py,v 1.1 2003/07/18 13:31:13 alga Exp $
"""
from __future__ import generators
import base64
from sha import sha
from zope.interface import implements
from zope.component import getService
from zope.context import ContextAwareDescriptors, ContextMethod
from zope.proxy import removeAllProxies
from zope.app.services.servicenames import SQLDatabaseConnections
from zope.app.interfaces.services.pluggableauth import IUserSchemafied
from zope.exceptions import NotFoundError
from persistence import Persistent
from interfaces import ISQLPrincipalSource
__metaclass__ = type
class SQLPrincipalSource(Persistent):
"""SQL based principal source for the Pluggable Authentication Service.
The table should be defined thus:
CREATE TABLE Users (
id SERIAL PRIMARY KEY,
login VARCHAR(255) UNIQUE,
title VARCHAR(255) NOT NULL,
description VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL
)
"""
ContextAwareDescriptors()
implements(ISQLPrincipalSource)
def __init__(self, connection=None, table="users"):
"""
connection is a registered SQL database connection name,
table is the name of the table the users are stored in.
"""
self.connection = connection
self.table = table
def _getConnection(self):
if not hasattr(self, '_v_connection'):
sqlservice = getService(self, SQLDatabaseConnections)
self._v_connection = sqlservice.getConnection(self.connection)
# Authentication should work for everyone, but we don't want to
# make SQL access public.
self._v_connection = removeAllProxies(self._v_connection)
return self._v_connection
def getPrincipal(self, id):
"See zope.app.interfaces.services.pluggableauth.IPrincipalSource"
conn = self._getConnection()
try:
return SQLPrincipal(conn, id, self.table)
except (IndexError, TypeError):
raise NotFoundError
def getPrincipals(self, name):
"See zope.app.interfaces.services.pluggableauth.IPrincipalSource"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT id FROM "%s" where login LIKE \'%%%s%%\'' %
(self.table, name))
result = []
for row in cursor.fetchall():
result.append(SQLPrincipal(conn, row[0], self.table))
return result
def __getitem__(self, key):
"See zope.interface.common.mapping.IItemMapping"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT id FROM "%s" WHERE login = \'%s\'' %
(self.table, key))
id = cursor.fetchone()[0]
return SQLPrincipal(conn, id, self.table)
def get(self, key, default=None):
"See zope.interface.common.mapping.IReadMapping"
if key is None:
return default
try:
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT id FROM "%s" WHERE login = \'%s\'' %
(self.table, key))
id = cursor.fetchone()[0]
return SQLPrincipal(conn, id, self.table)
#return self[key]
except (TypeError, IndexError):
return default
def __contains__(self, key):
"See zope.interface.common.mapping.IReadMapping"
if self.get(key):
return True
else:
return False
def keys(self):
"See zope.interface.common.mapping.IEnumerableMapping"
return tuple(self.__iter__())
def __iter__(self):
"See zope.interface.common.mapping.IEnumerableMapping"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT id FROM "%s"' % self.table)
for id, in cursor.fetchall():
principal = SQLPrincipal(conn, id, self.table)
yield principal.login
def values(self):
"See zope.interface.common.mapping.IEnumerableMapping"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT id FROM "%s"' % self.table)
result = []
for id, in cursor.fetchall():
principal = SQLPrincipal(conn, id, self.table)
result.append(principal)
return tuple(result)
def items(self):
"See zope.interface.common.mapping.IEnumerableMapping"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT id FROM "%s"' % self.table)
result = []
for id, in cursor.fetchall():
principal = SQLPrincipal(conn, id, self.table)
result.append((principal.login, principal))
return tuple(result)
def __len__(self):
"See zope.interface.common.mapping.IEnumerableMapping"
if not self.connection:
return 0
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('SELECT COUNT(*) FROM "%s"' % self.table)
return cursor.fetchone()[0]
def setObject(self, key, object):
"See zope.app.interfaces.container.IWriteContainer"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('INSERT INTO "%s" (login, password, title, description) '
'VALUES (\'%s\', \'%s\', \'%s\', \'%s\')' %
(self.table, object.login, object.password,
object.title, object.description))
return object.login
def __delitem__(self, key):
"See zope.app.interfaces.container.IWriteContainer"
conn = self._getConnection()
cursor = conn.cursor()
cursor.execute('DELETE FROM "%s" WHERE login = \'%s\'' %
(self.table, key))
def authenticate(self, login, password):
"See ILoginPasswordPrincipalSource"
principal = self.get(login, None)
if principal and principal.validate(password):
return principal
else:
return None
class SQLPrincipal:
"""This is a simple implementation of IUserSchemafied which issues
UPDATE SQL statements to the connection when the attributes are modified.
"""
implements(IUserSchemafied)
def __init__(self, connection, id, table="users"):
"""Arguments:
connection an IDBIConnection object
id the primary key of the user in the database
table database table with the columns named as
the attributes of IUserSchemafied
"""
self._connection = connection
self._table = table
self._id = id
cursor = self._connection.cursor()
cursor.execute(
'SELECT login, password, title, description from "%s" where id = %s'
% (table, id))
self._login, self._password, self._title, self._description = (
cursor.fetchone())
def validate(self, test_password):
"See zope.app.interfaces.services.pluggableauth.IUserSchemafied"
hash = base64.encodestring(sha(test_password).digest())[:-1]
return self._password == hash
def getId(self):
"See zope.app.interfaces.security.IPrincipal"
return self._id
def getTitle(self):
"See zope.app.interfaces.security.IPrincipal"
return self._title
def getDescription(self):
"See zope.app.interfaces.security.IPrincipal"
return self._description
def _getLogin(self): return self._login
def _getTitle(self): return self._title
def _getPassword(self): return self._password
def _getDescription(self): return self._description
def _setLogin(self, login):
self._set('login', login)
def _setTitle(self, title):
self._set('title', title)
def _setDescription(self, description):
self._set('description', description)
def _setPassword(self, password):
hash = base64.encodestring(sha(password).digest())[:-1]
self._set('password', hash)
def _set(self, attr, value):
setattr(self, '_' + attr, value)
self._connection.cursor().execute(
'UPDATE "%s" SET %s = \'%s\' WHERE id = %s' % (self._table, attr,
value, self._id))
def __cmp__(self, other):
return cmp(self.id, other.id)
id = property(getId)
title = property(_getTitle, _setTitle)
login = property(_getLogin, _setLogin)
password = property(_getPassword, _setPassword)
description = property(_getDescription, _setDescription)
=== Added File zopeproducts/sqlauth/configure.zcml ===
<zopeConfigure xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<content class=".SQLPrincipalSource">
<factory
id="zopeproducts.sqlauth.SQLPrincipalSource"
permission="zope.ManageServices"
/>
<allow
interface="zope.app.interfaces.container.IReadContainer"
/>
<require
permission="zope.ManageServices"
interface="zope.app.interfaces.container.IWriteContainer"
/>
<require
permission="zope.ManageServices"
interface="zopeproducts.sqlauth.interfaces.ISQLPrincipalSourceData"
/>
<allow
interface="zope.app.interfaces.services.pluggableauth.IPrincipalSource"
/>
</content>
<interface interface=".interfaces.ISQLPrincipalSource"/>
<content class=".SQLPrincipal">
<factory
id="zopeproducts.sqlauth.SQLPrincipal"
permission="zope.ManageServices"
/>
<allow
interface="zope.app.interfaces.services.pluggableauth.IUserSchemafied"
/>
<require
permission="zope.ManageServices"
set_schema="zope.app.interfaces.services.pluggableauth.IUserSchemafied"
/>
</content>
<browser:menuItem
menu="add_principal_source"
for="zope.app.interfaces.container.IAdding"
action="AddSQLPrincipalSourceForm"
title="SQL Principal Source"
description="SQL Principal Source"
/>
<browser:addform
schema="zopeproducts.sqlauth.interfaces.ISQLPrincipalSource"
label="Add SQL Principal source"
content_factory="zopeproducts.sqlauth.SQLPrincipalSource"
arguments="connection table"
fields="connection table"
name="AddSQLPrincipalSourceForm"
permission="zope.ManageServices" />
<browser:editform
name="edit.html"
menu="zmi_views" title="Edit"
label="Edit SQL data"
fields="connection table"
for="zopeproducts.sqlauth.interfaces.ISQLPrincipalSource"
schema="zopeproducts.sqlauth.interfaces.ISQLPrincipalSource"
permission="zope.ManageServices"
/>
</zopeConfigure>
=== Added File zopeproducts/sqlauth/interfaces.py ===
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Interfaces for the SQLPrincipalSource
$Id: interfaces.py,v 1.1 2003/07/18 13:31:13 alga Exp $
"""
import zope.schema
from zope.interface import Interface
from zope.app.interfaces.services.pluggableauth \
import IContainerPrincipalSource, ILoginPasswordPrincipalSource
from zope.app.interfaces.container import IContainerNamesContainer
from zope.app.i18n import ZopeMessageIDFactory as _
from zope.app.interfaces.content.sql import SQLConnectionName
class ISQLPrincipalSourceData(Interface):
connection = SQLConnectionName(
title=_("Connection"),
description=_("The SQL connection used"),
)
table = zope.schema.BytesLine(
title=_("Table"),
description=_(
"""The database table in which the users are stored. This
table has to have the columns "userid", "login" and
"password".
"""
),
)
class ISQLPrincipalSource(ISQLPrincipalSourceData, IContainerPrincipalSource,
IContainerNamesContainer, ILoginPasswordPrincipalSource):
pass