removed Zope products

This commit is contained in:
Emmanuel Viennet 2021-06-20 09:59:36 +02:00
parent 14d329fb0f
commit 8f91d5292c
125 changed files with 0 additions and 9576 deletions

View File

@ -1,5 +0,0 @@
Produits Zope2 anciens et adaptes pour ScoDoc
E. Viennet 2013

View File

@ -1,372 +0,0 @@
# ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 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 Lesser General Public
# License for more details.
# Import modules needed by _psycopg to allow tools like py2exe to do
# their work without bothering about the module dependencies.
import sys
import time
import db
import re
import Acquisition
import Shared.DC.ZRDB.Connection
from db import DB
from Globals import HTMLFile
from ExtensionClass import Base
from App.Dialogs import MessageDialog
from DateTime import DateTime
# ImageFile is deprecated in Zope >= 2.9
try:
from App.ImageFile import ImageFile
except ImportError:
# Zope < 2.9. If PIL's installed with a .pth file, we're probably
# hosed.
from ImageFile import ImageFile
# import psycopg and functions/singletons needed for date/time conversions
import psycopg2
from psycopg2 import NUMBER, STRING, ROWID, DATETIME
from psycopg2.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN, DATE
from psycopg2.extensions import TIME, INTERVAL
from psycopg2.extensions import new_type, register_type
# add a new connection to a folder
manage_addZPsycopgConnectionForm = HTMLFile('dtml/add',globals())
def manage_addZPsycopgConnection(self, id, title, connection_string,
zdatetime=None, tilevel=2,
encoding='', check=None, REQUEST=None):
"""Add a DB connection to a folder."""
self._setObject(id, Connection(id, title, connection_string,
zdatetime, check, tilevel, encoding))
if REQUEST is not None: return self.manage_main(self, REQUEST)
# the connection object
class Connection(Shared.DC.ZRDB.Connection.Connection):
"""ZPsycopg Connection."""
_isAnSQLConnection = 1
id = 'Psycopg2_database_connection'
database_type = 'Psycopg2'
meta_type = title = 'Z Psycopg 2 Database Connection'
icon = 'misc_/conn'
def __init__(self, id, title, connection_string,
zdatetime, check=None, tilevel=2, encoding='UTF-8'):
self.zdatetime = zdatetime
self.id = str(id)
self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding)
def factory(self):
return DB
## connection parameters editing ##
def edit(self, title, connection_string,
zdatetime, check=None, tilevel=2, encoding='UTF-8'):
self.title = title
self.connection_string = connection_string
self.zdatetime = zdatetime
self.tilevel = tilevel
self.encoding = encoding
if check: self.connect(self.connection_string)
manage_properties = HTMLFile('dtml/edit', globals())
def manage_edit(self, title, connection_string,
zdatetime=None, check=None, tilevel=2, encoding='UTF-8',
REQUEST=None):
"""Edit the DB connection."""
self.edit(title, connection_string, zdatetime,
check=check, tilevel=tilevel, encoding=encoding)
if REQUEST is not None:
msg = "Connection edited."
return self.manage_main(self,REQUEST,manage_tabs_message=msg)
def connect(self, s):
try:
self._v_database_connection.close()
except:
pass
# check psycopg version and raise exception if does not match
check_psycopg_version(psycopg2.__version__)
self._v_connected = ''
dbf = self.factory()
# TODO: let the psycopg exception propagate, or not?
self._v_database_connection = dbf(
self.connection_string, self.tilevel, self.get_type_casts(), self.encoding)
self._v_database_connection.open()
self._v_connected = DateTime()
return self
def get_type_casts(self):
# note that in both cases order *is* important
if self.zdatetime:
return ZDATETIME, ZDATE, ZTIME
else:
return DATETIME, DATE, TIME
## browsing and table/column management ##
manage_options = Shared.DC.ZRDB.Connection.Connection.manage_options
# + (
# {'label': 'Browse', 'action':'manage_browse'},)
#manage_tables = HTMLFile('dtml/tables', globals())
#manage_browse = HTMLFile('dtml/browse', globals())
info = None
def table_info(self):
return self._v_database_connection.table_info()
def __getitem__(self, name):
if name == 'tableNamed':
if not hasattr(self, '_v_tables'): self.tpValues()
return self._v_tables.__of__(self)
raise KeyError, name
def tpValues(self):
res = []
conn = self._v_database_connection
for d in conn.tables(rdb=0):
try:
name = d['TABLE_NAME']
b = TableBrowser()
b.__name__ = name
b._d = d
b._c = c
try:
b.icon = table_icons[d['TABLE_TYPE']]
except:
pass
r.append(b)
except:
pass
return res
def check_psycopg_version(version):
"""
Check that the psycopg version used is compatible with the zope adpter.
"""
try:
m = re.match(r'\d+\.\d+(\.\d+)?', version.split(' ')[0])
tver = tuple(map(int, m.group().split('.')))
except:
raise ImportError("failed to parse psycopg version %s" % version)
if tver < (2, 4):
raise ImportError("psycopg version %s is too old" % version)
if tver in ((2,4,2), (2,4,3)):
raise ImportError("psycopg version %s is known to be buggy" % version)
## database connection registration data ##
classes = (Connection,)
meta_types = ({'name':'Z Psycopg 2 Database Connection',
'action':'manage_addZPsycopgConnectionForm'},)
folder_methods = {
'manage_addZPsycopgConnection': manage_addZPsycopgConnection,
'manage_addZPsycopgConnectionForm': manage_addZPsycopgConnectionForm}
__ac_permissions__ = (
('Add Z Psycopg Database Connections',
('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),)
# add icons
misc_={'conn': ImageFile('icons/DBAdapterFolder_icon.gif', globals())}
for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin',
'int', 'float', 'date', 'time', 'datetime'):
misc_[icon] = ImageFile('icons/%s.gif' % icon, globals())
## zope-specific psycopg typecasters ##
# convert an ISO timestamp string from postgres to a Zope DateTime object
def _cast_DateTime(iso, curs):
if iso:
if iso in ['-infinity', 'infinity']:
return iso
else:
return DateTime(iso)
# convert an ISO date string from postgres to a Zope DateTime object
def _cast_Date(iso, curs):
if iso:
if iso in ['-infinity', 'infinity']:
return iso
else:
return DateTime(iso)
# Convert a time string from postgres to a Zope DateTime object.
# NOTE: we set the day as today before feeding to DateTime so
# that it has the same DST settings.
def _cast_Time(iso, curs):
if iso:
if iso in ['-infinity', 'infinity']:
return iso
else:
return DateTime(time.strftime('%Y-%m-%d %H:%M:%S',
time.localtime(time.time())[:3]+
time.strptime(iso[:8], "%H:%M:%S")[3:]))
# NOTE: we don't cast intervals anymore because they are passed
# untouched to Zope.
def _cast_Interval(iso, curs):
return iso
ZDATETIME = new_type((1184, 1114), "ZDATETIME", _cast_DateTime)
ZINTERVAL = new_type((1186,), "ZINTERVAL", _cast_Interval)
ZDATE = new_type((1082,), "ZDATE", _cast_Date)
ZTIME = new_type((1083,), "ZTIME", _cast_Time)
## table browsing helpers ##
class TableBrowserCollection(Acquisition.Implicit):
pass
class Browser(Base):
def __getattr__(self, name):
try:
return self._d[name]
except KeyError:
raise AttributeError, name
class values:
def len(self):
return 1
def __getitem__(self, i):
try:
return self._d[i]
except AttributeError:
pass
self._d = self._f()
return self._d[i]
class TableBrowser(Browser, Acquisition.Implicit):
icon = 'what'
Description = check = ''
info = HTMLFile('table_info', globals())
menu = HTMLFile('table_menu', globals())
def tpValues(self):
v = values()
v._f = self.tpValues_
return v
def tpValues_(self):
r=[]
tname=self.__name__
for d in self._c.columns(tname):
b=ColumnBrowser()
b._d=d
try: b.icon=field_icons[d['Type']]
except: pass
b.TABLE_NAME=tname
r.append(b)
return r
def tpId(self): return self._d['TABLE_NAME']
def tpURL(self): return "Table/%s" % self._d['TABLE_NAME']
def Name(self): return self._d['TABLE_NAME']
def Type(self): return self._d['TABLE_TYPE']
manage_designInput=HTMLFile('designInput',globals())
def manage_buildInput(self, id, source, default, REQUEST=None):
"Create a database method for an input form"
args=[]
values=[]
names=[]
columns=self._columns
for i in range(len(source)):
s=source[i]
if s=='Null': continue
c=columns[i]
d=default[i]
t=c['Type']
n=c['Name']
names.append(n)
if s=='Argument':
values.append("<dtml-sqlvar %s type=%s>'" %
(n, vartype(t)))
a='%s%s' % (n, boboType(t))
if d: a="%s=%s" % (a,d)
args.append(a)
elif s=='Property':
values.append("<dtml-sqlvar %s type=%s>'" %
(n, vartype(t)))
else:
if isStringType(t):
if find(d,"\'") >= 0: d=join(split(d,"\'"),"''")
values.append("'%s'" % d)
elif d:
values.append(str(d))
else:
raise ValueError, (
'no default was given for <em>%s</em>' % n)
class ColumnBrowser(Browser):
icon='field'
def check(self):
return ('\t<input type=checkbox name="%s.%s">' %
(self.TABLE_NAME, self._d['Name']))
def tpId(self): return self._d['Name']
def tpURL(self): return "Column/%s" % self._d['Name']
def Description(self):
d=self._d
if d['Scale']:
return " %(Type)s(%(Precision)s,%(Scale)s) %(Nullable)s" % d
else:
return " %(Type)s(%(Precision)s) %(Nullable)s" % d
table_icons={
'TABLE': 'table',
'VIEW':'view',
'SYSTEM_TABLE': 'stable',
}
field_icons={
NUMBER.name: 'i',
STRING.name: 'text',
DATETIME.name: 'date',
INTEGER.name: 'int',
FLOAT.name: 'float',
BOOLEAN.name: 'bin',
ROWID.name: 'int'
}

View File

@ -1,29 +0,0 @@
# ZPsycopgDA/__init__.py - ZPsycopgDA Zope product
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 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 Lesser General Public
# License for more details.
# Import modules needed by _psycopg to allow tools like py2exe to do
# their work without bothering about the module dependencies.
__doc__ = "ZPsycopg Database Adapter Registration."
__version__ = '2.4.6'
import DA
def initialize(context):
context.registerClass(
DA.Connection,
permission = 'Add Z Psycopg 2 Database Connections',
constructors = (DA.manage_addZPsycopgConnectionForm,
DA.manage_addZPsycopgConnection),
icon = 'icons/DBAdapterFolder_icon.gif')

View File

@ -1,209 +0,0 @@
# ZPsycopgDA/db.py - query execution
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 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 Lesser General Public
# License for more details.
# Import modules needed by _psycopg to allow tools like py2exe to do
# their work without bothering about the module dependencies.
from Shared.DC.ZRDB.TM import TM
from Shared.DC.ZRDB import dbi_db
from ZODB.POSException import ConflictError
import site
import pool
import psycopg2
from psycopg2.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN, DATE, TIME
from psycopg2.extensions import TransactionRollbackError, register_type
from psycopg2 import NUMBER, STRING, ROWID, DATETIME
# the DB object, managing all the real query work
class DB(TM, dbi_db.DB):
_p_oid = _p_changed = _registered = None
def __init__(self, dsn, tilevel, typecasts, enc='utf-8'):
self.dsn = dsn
self.tilevel = tilevel
self.typecasts = typecasts
if enc is None or enc == "":
self.encoding = "utf-8"
else:
self.encoding = enc
self.failures = 0
self.calls = 0
self.make_mappings()
def getconn(self, init=True):
# if init is False we are trying to get hold on an already existing
# connection, so we avoid to (re)initialize it risking errors.
conn = pool.getconn(self.dsn)
if init:
# use set_session where available as in these versions
# set_isolation_level generates an extra query.
if psycopg2.__version__ >= '2.4.2':
conn.set_session(isolation_level=int(self.tilevel))
else:
conn.set_isolation_level(int(self.tilevel))
conn.set_client_encoding(self.encoding)
for tc in self.typecasts:
register_type(tc, conn)
return conn
def putconn(self, close=False):
try:
conn = pool.getconn(self.dsn, False)
except AttributeError:
pass
pool.putconn(self.dsn, conn, close)
def getcursor(self):
conn = self.getconn(False)
return conn.cursor()
def _finish(self, *ignored):
try:
conn = self.getconn(False)
conn.commit()
self.putconn()
except AttributeError:
pass
def _abort(self, *ignored):
try:
conn = self.getconn(False)
conn.rollback()
self.putconn()
except AttributeError:
pass
def open(self):
# this will create a new pool for our DSN if not already existing,
# then get and immediately release a connection
self.getconn()
self.putconn()
def close(self):
# FIXME: if this connection is closed we flush all the pool associated
# with the current DSN; does this makes sense?
pool.flushpool(self.dsn)
def sortKey(self):
return 1
def make_mappings(self):
"""Generate the mappings used later by self.convert_description()."""
self.type_mappings = {}
for t, s in [(INTEGER,'i'), (LONGINTEGER, 'i'), (NUMBER, 'n'),
(BOOLEAN,'n'), (ROWID, 'i'),
(DATETIME, 'd'), (DATE, 'd'), (TIME, 'd')]:
for v in t.values:
self.type_mappings[v] = (t, s)
def convert_description(self, desc, use_psycopg_types=False):
"""Convert DBAPI-2.0 description field to Zope format."""
items = []
for name, typ, width, ds, p, scale, null_ok in desc:
m = self.type_mappings.get(typ, (STRING, 's'))
items.append({
'name': name,
'type': use_psycopg_types and m[0] or m[1],
'width': width,
'precision': p,
'scale': scale,
'null': null_ok,
})
return items
## tables and rows ##
def tables(self, rdb=0, _care=('TABLE', 'VIEW')):
self._register()
c = self.getcursor()
c.execute(
"SELECT t.tablename AS NAME, 'TABLE' AS TYPE "
" FROM pg_tables t WHERE tableowner <> 'postgres' "
"UNION SELECT v.viewname AS NAME, 'VIEW' AS TYPE "
" FROM pg_views v WHERE viewowner <> 'postgres' "
"UNION SELECT t.tablename AS NAME, 'SYSTEM_TABLE\' AS TYPE "
" FROM pg_tables t WHERE tableowner = 'postgres' "
"UNION SELECT v.viewname AS NAME, 'SYSTEM_TABLE' AS TYPE "
"FROM pg_views v WHERE viewowner = 'postgres'")
res = []
for name, typ in c.fetchall():
if typ in _care:
res.append({'TABLE_NAME': name, 'TABLE_TYPE': typ})
self.putconn()
return res
def columns(self, table_name):
self._register()
c = self.getcursor()
try:
r = c.execute('SELECT * FROM "%s" WHERE 1=0' % table_name)
except:
return ()
self.putconn()
return self.convert_description(c.description, True)
## query execution ##
def query(self, query_string, max_rows=None, query_data=None):
self._register()
self.calls = self.calls+1
desc = ()
res = []
nselects = 0
c = self.getcursor()
try:
for qs in [x for x in query_string.split('\0') if x]:
try:
if query_data:
c.execute(qs, query_data)
else:
c.execute(qs)
except TransactionRollbackError:
# Ha, here we have to look like we are the ZODB raising conflict errrors, raising ZPublisher.Publish.Retry just doesn't work
#logging.debug("Serialization Error, retrying transaction", exc_info=True)
raise ConflictError("TransactionRollbackError from psycopg2")
except psycopg2.OperationalError:
#logging.exception("Operational error on connection, closing it.")
try:
# Only close our connection
self.putconn(True)
except:
#logging.debug("Something went wrong when we tried to close the pool", exc_info=True)
pass
if c.description is not None:
nselects += 1
if c.description != desc and nselects > 1:
raise psycopg2.ProgrammingError(
'multiple selects in single query not allowed')
if max_rows:
res = c.fetchmany(max_rows)
else:
res = c.fetchall()
desc = c.description
self.failures = 0
except StandardError, err:
self._abort()
raise err
return self.convert_description(desc), res

View File

@ -1,108 +0,0 @@
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Z Psycopg 2 Database Connection',
help_product='ZPsycopgDA',
help_topic='ZPsycopgDA-Method-Add.stx'
)">
<p class="form-help">
A Zope Psycopg 2 Database Connection is used to connect and execute
queries on a PostgreSQL database.
</p>
<p class="form-help">
In the form below <em>Connection String</em> (also called the Data Source Name
or DSN for short) is a string... (TODO: finish docs)
</p>
<form action="manage_addZPsycopgConnection" 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"
value="Psycopg2_database_connection" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40"
value="Z Psycopg 2 Database Connection"/>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Connection string
</div>
</td>
<td align="left" valign="top">
<input type="text" name="connection_string" size="40" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Connect immediately
</div>
</td>
<td align="left" valign="top">
<input type="checkbox" name="check" value="YES" checked="YES" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Use Zope's internal DateTime
</div>
</td>
<td align="left" valign="top">
<input type="checkbox" name="zdatetime" value="YES" checked="YES" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Transaction isolation level
</div>
</td>
<td align="left" valign="top">
<select name="tilevel:int">
<option value="4">Read uncommitted</option>
<option value="1">Read committed</option>
<option value="2" selected="YES">Repeatable read</option>
<option value="3">Serializable</option>
</select>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Encoding
</div>
</td>
<td align="left" valign="top">
<input type="text" name="encoding" size="40" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="2">
<div class="form-element">
<input class="form-element" type="submit" name="submit" value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>

View File

@ -1,11 +0,0 @@
<html>
<head><title><dtml-var title_or_id >tables</title></head>
<body bgcolor="#FFFFFF" link="#000099" vlink="#555555" alink="#77003B">
<dtml-var manage_tabs>
<dtml-tree header="info">
<IMG SRC="<dtml-var SCRIPT_NAME >/misc_/ZPsycopgDA/<dtml-var icon>"
ALT="<dtml-var Type>" BORDER="0">
<dtml-var Name><dtml-var Description>
</dtml-tree>
</body>
</html>

View File

@ -1,84 +0,0 @@
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<form action="manage_edit" method="POST">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40"
value="&dtml-title;"/>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Connection string
</div>
</td>
<td align="left" valign="top">
<input type="text" name="connection_string" size="40"
value="&dtml-connection_string;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Use Zope's internal DateTime
</div>
</td>
<td align="left" valign="top">
<input type="checkbox" name="zdatetime" value="YES"
<dtml-if expr="zdatetime">checked="YES"</dtml-if> />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Transaction isolation level
</div>
</td>
<td align="left" valign="top">
<select name="tilevel:int">
<option value="4"
<dtml-if expr="tilevel==4">selected="YES"</dtml-if>>
Read uncommitted</option>
<option value="1"
<dtml-if expr="tilevel==1">selected="YES"</dtml-if>>
Read committed</option>
<option value="2"
<dtml-if expr="tilevel==2">selected="YES"</dtml-if>>
Repeatable read</option>
<option value="3"
<dtml-if expr="tilevel==3">selected="YES"</dtml-if>>
Serializable</option>
</select>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Encoding
</div>
</td>
<td align="left" valign="top">
<input type="text" name="encoding" size="40"
value="&dtml-encoding;" />
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="2">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Save Changes " />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>

View File

@ -1,7 +0,0 @@
<dtml-var standard_html_header>
<dtml-var TABLE_TYPE><dtml-if TABLE_OWNER>
owned by <dtml-var TABLE_OWNER></dtml-if>
<dtml-if REMARKS><br><dtml-var REMARKS></dtml-if>
<dtml-var standard_html_footer>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 B

View File

@ -1,193 +0,0 @@
# ZPsycopgDA/pool.py - ZPsycopgDA Zope product: connection pooling
#
# Copyright (C) 2004-2010 Federico Di Gregorio <fog@debian.org>
#
# psycopg2 is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# psycopg2 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 Lesser General Public
# License for more details.
# Import modules needed by _psycopg to allow tools like py2exe to do
# their work without bothering about the module dependencies.
# All the connections are held in a pool of pools, directly accessible by the
# ZPsycopgDA code in db.py.
import threading
import psycopg2
from psycopg2.pool import PoolError
class AbstractConnectionPool(object):
"""Generic key-based pooling code."""
def __init__(self, minconn, maxconn, *args, **kwargs):
"""Initialize the connection pool.
New 'minconn' connections are created immediately calling 'connfunc'
with given parameters. The connection pool will support a maximum of
about 'maxconn' connections.
"""
self.minconn = minconn
self.maxconn = maxconn
self.closed = False
self._args = args
self._kwargs = kwargs
self._pool = []
self._used = {}
self._rused = {} # id(conn) -> key map
self._keys = 0
for i in range(self.minconn):
self._connect()
def _connect(self, key=None):
"""Create a new connection and assign it to 'key' if not None."""
conn = psycopg2.connect(*self._args, **self._kwargs)
if key is not None:
self._used[key] = conn
self._rused[id(conn)] = key
else:
self._pool.append(conn)
return conn
def _getkey(self):
"""Return a new unique key."""
self._keys += 1
return self._keys
def _getconn(self, key=None):
"""Get a free connection and assign it to 'key' if not None."""
if self.closed: raise PoolError("connection pool is closed")
if key is None: key = self._getkey()
if key in self._used:
return self._used[key]
if self._pool:
self._used[key] = conn = self._pool.pop()
self._rused[id(conn)] = key
return conn
else:
if len(self._used) == self.maxconn:
raise PoolError("connection pool exausted")
return self._connect(key)
def _putconn(self, conn, key=None, close=False):
"""Put away a connection."""
if self.closed: raise PoolError("connection pool is closed")
if key is None: key = self._rused[id(conn)]
if not key:
raise PoolError("trying to put unkeyed connection")
if len(self._pool) < self.minconn and not close:
self._pool.append(conn)
else:
conn.close()
# here we check for the presence of key because it can happen that a
# thread tries to put back a connection after a call to close
if not self.closed or key in self._used:
del self._used[key]
del self._rused[id(conn)]
def _closeall(self):
"""Close all connections.
Note that this can lead to some code fail badly when trying to use
an already closed connection. If you call .closeall() make sure
your code can deal with it.
"""
if self.closed: raise PoolError("connection pool is closed")
for conn in self._pool + list(self._used.values()):
try:
conn.close()
except:
pass
self.closed = True
class PersistentConnectionPool(AbstractConnectionPool):
"""A pool that assigns persistent connections to different threads.
Note that this connection pool generates by itself the required keys
using the current thread id. This means that until a thread puts away
a connection it will always get the same connection object by successive
`!getconn()` calls. This also means that a thread can't use more than one
single connection from the pool.
"""
def __init__(self, minconn, maxconn, *args, **kwargs):
"""Initialize the threading lock."""
import threading
AbstractConnectionPool.__init__(
self, minconn, maxconn, *args, **kwargs)
self._lock = threading.Lock()
# we we'll need the thread module, to determine thread ids, so we
# import it here and copy it in an instance variable
import thread
self.__thread = thread
def getconn(self):
"""Generate thread id and return a connection."""
key = self.__thread.get_ident()
self._lock.acquire()
try:
return self._getconn(key)
finally:
self._lock.release()
def putconn(self, conn=None, close=False):
"""Put away an unused connection."""
key = self.__thread.get_ident()
self._lock.acquire()
try:
if not conn: conn = self._used[key]
self._putconn(conn, key, close)
finally:
self._lock.release()
def closeall(self):
"""Close all connections (even the one currently in use.)"""
self._lock.acquire()
try:
self._closeall()
finally:
self._lock.release()
_connections_pool = {}
_connections_lock = threading.Lock()
def getpool(dsn, create=True):
_connections_lock.acquire()
try:
if not _connections_pool.has_key(dsn) and create:
_connections_pool[dsn] = \
PersistentConnectionPool(4, 200, dsn)
finally:
_connections_lock.release()
return _connections_pool[dsn]
def flushpool(dsn):
_connections_lock.acquire()
try:
_connections_pool[dsn].closeall()
del _connections_pool[dsn]
finally:
_connections_lock.release()
def getconn(dsn, create=True):
return getpool(dsn, create=create).getconn()
def putconn(dsn, conn, close=False):
getpool(dsn).putconn(conn, close=close)

View File

@ -1,47 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: __init__.py,v 1.1 2004/11/10 14:15:34 akm Exp $
#import etcAuthSource
#import httpsAuthSource
#import mysqlAuthSource
import pgAuthSource
#import pgAuthSourceAlt
#import radiusAuthSource
#import smbAuthSource
#import usAuthSource
#import zodbAuthSource
#import zodbBTreeAuthSource
#
# These have special requirements for external libraries
# that my not be present.
#
# try:
# import nisAuthSource
# except:
# pass
# try:
# import LDAPAuthSource
# except:
# pass

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2004/11/10 14:15:36 akm Exp $
import pgAuthSource

View File

@ -1,40 +0,0 @@
<dtml-var "DialogHeader(_.None,_,DialogTitle='Add Postgresql Authentication Source')">
<FORM ACTION="&dtml-URL;" METHOD="POST">
<dtml-in "REQUEST.form.keys()">
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-in>
<input type="HIDDEN" name="doProp" value="1">
<TABLE CELLSPACING="2">
<tr><th><dtml-babel src="'en'">Database Connection</dtml-babel>:</th>
<td>
<select name="pgauth_connection">
<dtml-in "SQLConnectionIDs()">
<option value="<dtml-var sequence-item>">
<dtml-var sequence-key></option>
</dtml-in>
</select>
</td>
</tr>
<tr>
<th><dtml-babel src="'en'">Table Name</dtml-babel>:</th>
<td><input type="text" name="pgauth_table" value="passwd"></td>
</tr>
<tr>
<th><dtml-babel src="'en'">Username Column</dtml-babel>:</th>
<td><input type="text" name="pgauth_usernameColumn" value="username"></td>
</tr>
<tr>
<th><dtml-babel src="'en'">Password Column</dtml-babel>:</th>
<td><input type="text" name="pgauth_passwordColumn" value="password"></td>
</tr>
<tr>
<th><dtml-babel src="'en'">Roles Column</dtml-babel>:</th>
<td><input type="text" name="pgauth_rolesColumn" value="roles"></td>
</tr>
<TR>
<TD></TD>
<TD><BR><INPUT TYPE="SUBMIT" VALUE="<dtml-babel src="'en'">Add</dtml-babel>"></TD>
</TR>
</TABLE>
</FORM>
<dtml-var DialogFooter>

View File

@ -1,37 +0,0 @@
<dtml-var "DialogHeader(_.None,_,DialogTitle='Postgresql Authentication Source',dialog_width='100%')">
<dtml-var manage_tabs>
<FORM ACTION="manage_editAuthSource" METHOD="POST">
<TABLE CELLSPACING="2">
<tr><th><dtml-babel src="'en'">Database Connection</dtml-babel>:</th>
<td>
<select name="pgauth_connection">
<dtml-in "SQLConnectionIDs()">
<option value="<dtml-var sequence-item>"<dtml-if "currentAuthSource.connection==_['sequence-item']"> SELECTED</dtml-if>>
<dtml-var sequence-key></option>
</dtml-in>
</select>
</td>
</tr>
<tr>
<th><dtml-babel src="'en'">Table Name</dtml-babel>:</th>
<td><input type="text" name="pgauth_table" value="<dtml-var "currentAuthSource.table">"></td>
</tr>
<tr>
<th><dtml-babel src="'en'">Username Column</dtml-babel>:</th>
<td><input type="text" name="pgauth_usernameColumn" value="<dtml-var "currentAuthSource.usernameColumn">"></td>
</tr>
<tr>
<th><dtml-babel src="'en'">Password Column</dtml-babel>:</th>
<td><input type="text" name="pgauth_passwordColumn" value="<dtml-var "currentAuthSource.passwordColumn">"></td>
</tr>
<tr>
<th><dtml-babel src="'en'">Roles Column</dtml-babel>:</th>
<td><input type="text" name="pgauth_rolesColumn" value="<dtml-var "currentAuthSource.rolesColumn">"></td>
</tr>
<TR>
<TD></TD>
<TD><BR><INPUT TYPE="SUBMIT" VALUE=" <dtml-babel src="'en'">Edit</dtml-babel> "></TD>
</TR>
</TABLE>
</FORM>
<dtml-var DialogFooter>

View File

@ -1,333 +0,0 @@
#
# Extensible User Folder
#
# Postgres Authentication Source for exUserFolder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: pgAuthSource.py,v 1.1 2004/11/10 14:15:36 akm Exp $
#
# This class only authenticates users, it stores no properties.
#
import string,Acquisition
from Globals import HTMLFile, MessageDialog, INSTANCE_HOME
from OFS.Folder import Folder
from Products.ZSQLMethods.SQL import SQL
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import PluginRegister
try:
from crypt import crypt
except:
from Products.exUserFolder.fcrypt.fcrypt import crypt
# debug XXX
# def xLOG(msg):
# f = open('/tmp/debug.log','a')
# f.write(msg+'\n')
# f.close()
def manage_addpgAuthSource(self, REQUEST):
""" Add a Postgres Auth Source """
connection=REQUEST['pgauth_connection']
table=REQUEST['pgauth_table']
usernameColumn=REQUEST['pgauth_usernameColumn']
passwordColumn=REQUEST['pgauth_passwordColumn']
rolesColumn=REQUEST['pgauth_rolesColumn']
o = pgAuthSource(connection, table, usernameColumn, passwordColumn,
rolesColumn)
self._setObject('pgAuthSource', o, None, None, 0)
o=getattr(self,'pgAuthSource')
if hasattr(o, 'postInitialisation'):
o.postInitialisation(REQUEST)
self.currentAuthSource=o
return ''
manage_addpgAuthSourceForm=HTMLFile('manage_addpgAuthSourceForm', globals())
manage_editpgAuthSourceForm=HTMLFile('manage_editpgAuthSourceForm', globals())
class pgAuthSource(Folder):
""" Authenticate Users against a Postgres Database """
meta_type='Authentication Source'
title='Postgresql Authentication'
icon ='misc_/exUserFolder/exUserFolderPlugin.gif'
manage_tabs=Acquisition.Acquired
manage_editForm=manage_editpgAuthSourceForm
#
# You can define this to go off and do the authentication instead of
# using the basic one inside the User Object
#
remoteAuthMethod=None
def __init__(self, connection, table, usernameColumn, passwordColumn,
rolesColumn):
self.id='pgAuthSource'
self.connection=connection
self.table=table
self.usernameColumn=usernameColumn
self.passwordColumn=passwordColumn
self.rolesColumn=rolesColumn
self.addSQLQueries()
def manage_editAuthSource(self, REQUEST):
""" Edit a Postgres Auth Source """
self.connection=REQUEST['pgauth_connection']
self.table=REQUEST['pgauth_table']
self.usernameColumn=REQUEST['pgauth_usernameColumn']
self.passwordColumn=REQUEST['pgauth_passwordColumn']
self.rolesColumn=REQUEST['pgauth_rolesColumn']
self.delSQLQueries()
self.addSQLQueries() # Re-add queries with new parameters
def createUser(self, username, password, roles):
""" Add A Username """
if type(roles) != type([]):
if roles:
roles=list(roles)
else:
roles=[]
rolestring=''
for role in roles:
rolestring=rolestring+role+','
rolestring=rolestring[:-1]
secret=self.cryptPassword(username, password)
self.sqlInsertUser(username=username,
password=secret,
roles=rolestring)
self._v_lastUser={}
def updateUser(self, username, password, roles):
if type(roles) != type([]):
if roles:
roles=list(roles)
else:
roles=[]
rolestring=''
for role in roles:
print role
rolestring=rolestring+role+','
rolestring=rolestring[:-1]
# Don't change passwords if it's null
if password:
secret=self.cryptPassword(username, password)
self.sqlUpdateUserPassword(username=username,
password=secret)
self.sqlUpdateUser(username=username,
roles=rolestring)
self._v_lastUser={}
def delSQLQueries(self):
sqllist=self.objectIds('Z SQL Method')
self.manage_delObjects(ids=sqllist)
def addSQLQueries(self):
sqlListUsers=SQL(
'sqlListUsers',
'List All Users',
self.connection,
'table=%s'%(self.table),
_sqlListUsers)
self._setObject('sqlListUsers', sqlListUsers)
sqlListOneUser=SQL(
'sqlListOneUser',
'List ONE User',
self.connection,
'table=%s usernameColumn=%s username:string'%(
self.table, self.usernameColumn),
_sqlListOneUser)
self._setObject('sqlListOneUser', sqlListOneUser)
sqlDeleteOneUser=SQL(
'sqlDeleteOneUser',
'Delete One User',
self.connection,
'table=%s usernameColumn=%s username:string'%(
self.table,self.usernameColumn),
_sqlDeleteOneUser)
self._setObject('sqlDeleteOneUser', sqlDeleteOneUser)
sqlInsertUser=SQL(
'sqlInsertUser',
'Insert One User',
self.connection,
'table=%s usernameColumn=%s passwordColumn=%s rolesColumn=%s username:string password:string roles:string'%(
self.table, self.usernameColumn, self.passwordColumn, self.rolesColumn),
_sqlInsertUser)
self._setObject('sqlInsertUser', sqlInsertUser)
sqlUpdateUser=SQL(
'sqlUpdateUser',
'Update User',
self.connection,
'table=%s rolesColumn=%s username:string roles:string'%(self.table, self.rolesColumn),
_sqlUpdateUser)
self._setObject('sqlUpdateUser', sqlUpdateUser)
sqlUpdateUserPassword=SQL(
'sqlUpdateUserPassword',
'Update just the password',
self.connection,
'table=%s usernameColumn=%s passwordColumn=%s username:string password:string'%(self.table, self.usernameColumn, self.passwordColumn),
_sqlUpdateUserPassword)
self._setObject('sqlUpdateUserPassword', sqlUpdateUserPassword)
def cryptPassword_old(self, username, password):
salt =username[:2]
secret = crypt(password, salt)
return secret
def deleteUsers(self, userids):
for uid in userids:
self.sqlDeleteOneUser(username=uid)
self._v_lastUser={}
def listUserNames(self):
"""Returns a real list of user names """
users = []
result=self.sqlListUsers()
for n in result:
username=sqlattr(n,self.usernameColumn)
users.append(username)
return users
def listUsers(self):
"""Returns a list of user names or [] if no users exist"""
users = []
result=self.sqlListUsers()
for n in result:
roles=[]
username=sqlattr(n,self.usernameColumn)
if sqlattr(n, self.rolesColumn):
roles=string.split(sqlattr(n,self.rolesColumn),',')
password=sqlattr(n, self.passwordColumn)
N={'username':username, 'password':password, 'roles':roles}
users.append(N)
return users
def listOneUser(self,username):
#xLOG('pg.listOneUser(%s)' % username)
if getattr(self, '_v_lastUser', {}):
if self._v_lastUser['username']==username:
return self._v_lastUser['users']
#xLOG('pg.listOneUser continuing')
users = []
result=self.sqlListOneUser(username=username)
#xLOG('pg.listOneUser result=%s' % result)
for n in result:
roles=[]
username=sqlattr(n,self.usernameColumn)
password=sqlattr(n,self.passwordColumn)
if sqlattr(n, self.rolesColumn):
roles=string.split(sqlattr(n,self.rolesColumn),',') #Andreas
N={'username':username, 'password':password, 'roles':roles}
users.append(N)
self._v_lastUser={}
self._v_lastUser['username']=username
self._v_lastUser['users']=users
return users
def postInitialisation(self, REQUEST):
self._v_lastUser={}
pgAuthReg=PluginRegister('pgAuthSource', 'Postgresql Authentication Source',
pgAuthSource, manage_addpgAuthSourceForm,
manage_addpgAuthSource,
manage_editpgAuthSourceForm)
exUserFolder.authSources['pgAuthSource']=pgAuthReg
from string import upper, lower
import Missing
mt=type(Missing.Value)
def typeconv(val):
if type(val)==mt:
return ''
return val
def sqlattr(ob, attr):
name=attr
if hasattr(ob, attr):
return typeconv(getattr(ob, attr))
attr=upper(attr)
if hasattr(ob, attr):
return typeconv(getattr(ob, attr))
attr=lower(attr)
if hasattr(ob, attr):
return typeconv(getattr(ob, attr))
raise NameError, name
_sqlListUsers="""
SELECT * FROM <dtml-var table>
"""
_sqlListOneUser="""
SELECT * FROM <dtml-var table>
where <dtml-var usernameColumn>=<dtml-sqlvar username type=string>
"""
_sqlDeleteOneUser="""
DELETE FROM <dtml-var table>
where <dtml-var usernameColumn>=<dtml-sqlvar username type=string>
"""
_sqlInsertUser="""
INSERT INTO <dtml-var table> (<dtml-var usernameColumn>, <dtml-var passwordColumn>, <dtml-var rolesColumn>)
VALUES (<dtml-sqlvar username type=string>,
<dtml-sqlvar password type=string>,
<dtml-sqlvar roles type=string>)
"""
_sqlUpdateUserPassword="""
UPDATE <dtml-var table> set <dtml-var passwordColumn>=<dtml-sqlvar password type=string>
WHERE <dtml-var usernameColumn>=<dtml-sqlvar username type=string>
"""
_sqlUpdateUser="""
UPDATE <dtml-var table> set <dtml-var rolesColumn>=<dtml-sqlvar roles type=string>
WHERE <dtml-var usernameColumn>=<dtml-sqlvar username type=string>
"""

View File

@ -1,865 +0,0 @@
Changes for 0.50.1
Add a README.Upgrading file to explain the impact of the 0.50.0 source
restructure, since people don't seem to be reading this file. --akm
Fix the default docLogin to use &dtml-URL as the default destination.
I porked the fcrypt import. It obviously doesn't get imported here since
I have a crypt module installed. -- akm
Fixed; https://sourceforge.net/tracker/?func=detail&aid=1084903&group_id=36318&atid=416446
thanks to vigine -- akm
Changes for 0.50.0
Restructured Source Tree. This will make this version incompatible with
previous versions, as the classes have moved. This breaks upgrading existing
installs unless you keep the old classes around. If you only use external
Auth/Prop/Group sources, you will probably be unaffected.
o Auth Sources moved to single directory
o Prop Sources moved to single directory
o Group Sources moved to single directory
o Docs moved to doc directory
--akm
Added Pluggable Crypto methods. Any authSource that contains a
cryptPassword method, will have it's method called, otherwise the
method selected by the user is called. --akm
Removed the cryptPassword method from existing Auth Sources. --akm
docLoginRedirect is no longer used. --akm
Changes for 0.20.2
BLAH! I missed some LDAP changes! --akm
Changes for 0.20.1
Fix import problem for pgPropSource --akm
Add performance boost to pgAuthSource and pgPropSource --akm
Make zodbAuthSource.listUsernames return a list. --akm
Update some LDAP Auth source bugs. --akm
Change references to "Authorisation" to "Authentication" since XUF
auth sources authenticate, they don't authorise. --akm
Changed the <h3> tags to <b> tags in the manage_adds.
Changes for 0.20.0
Fix:
https://sourceforge.net/tracker/index.php?func=detail&aid=547327&group_id=36318&atid=416446
https://sourceforge.net/tracker/index.php?func=detail&aid=616485&group_id=36318&atid=416448
https://sourceforge.net/tracker/index.php?func=detail&aid=594081&group_id=36318&atid=416448
https://sourceforge.net/tracker/index.php?func=detail&aid=594526&group_id=36318&atid=416448
Added LDAPAuthSource, based on the auth_ldap module for Apache
(http://www.rudedog.org/auth_ldap/) and the NDS Auth Source of
Phil Harris (AKA ftmpsh). This is only lightly tested, I don't have
the LDAP resources here to test all the features. Binding using uid/
cn and using various filters works (if the userPassword item is
present). This needs more testing by people with better LDAP setups
that I do. --akm
Padded docLoginRedirect to prevent IE from displaying "Friendly" error
messages when -D flag not present when running Zope --akm.
Update UZG to contain entry for LDAPAuthSource. Reformat text
slightly. --akm
Propogate "unable to auth" here requests up. This means the Manager
doesn't get locked out in cookie mode after adding an XUF instance.
It also means that people using a non-existant username at this level
get thrown up a level higher. This might not be what people want to
happen. --akm
Added method makeRedirectPath which is called from docLoginRedirect.
This makes the destination include any querystring that was present
when needing to redirect. -- akm.
Removed some Class globals from exUseFolder.py. These are now set
in __set_state__ if not present in the class so that upgrading users
don't get a crash (hopefully). -- akm.
pgPropSource was losing track of properties under heavy load.
Only noticable if you were setting and deleting a lot of temporary
properties. There is a global property timeout for pgPropSource. --akm
Jason Gibson <jason.gibson@sbcglobal.net> provided a nisAuthSource,
I've added it here --akm.
Refactored validate method to behave a lot more like BasicUserFolder.
Among other things, this fixes the issue where a local role could not
be granted to a user and granted permissions on the same object. --mb
Add NuxUserGroups support (previously on NuxUserGroups_support_branch)
and group sources. --bmh, mb
Now passes authFailedCode to Membership Login Page, The Default Login
Page as defined in the README.Membership will correctly display reason
for login being required --cab
Fixed Edit management pages for user-supplied auth and property
sources --bmh
Removed overriding of __len__ to return the number of users. This was
causing performance problems during authentication. See
http://sourceforge.net/mailarchive/message.php?msg_id=2230743 for
details. WARNING: this means using len(acl_users) to get the number
of users will no longer work! If you were using this trick, please
use len(acl_users.listUsers()) instead. --bmh
Make title property editable --bmh
Make Group Sources changeable dynamically after the acl_users folder has
been created --bmh
Inital import of https Auth source. Also, added a listUsers method
to the zodbBTreeProps source to support listUsers. -- jsb <jonah at cloud9.net>
Changes for 0.10.10
Added mysql Auth and mysql Prop source and mysql.sql schema. Just a
copy of the appropriate pg source with sql that works with myqsl -cab
Fixed negative user cache lookup in std_validade so that it actually
works for users being authenticated thru basic auth, especially if
they're authenticating in outer user folders -- rochael
Made smbAuthSource catch NetBIOSTimeout errors during authentication -- rochael
Fixed dtml/mainUser.dtml to be virtualhost-sensitive when displaying user
icons -- rochael
Updated UZG per user request. Fixed numbering, added information about
addition parameters like Negative Caching.
Changes for 0.10.9
Made dummyZBabelTag compatible to replace the NoBabel in OrderedFolder
while keeping its functionality in XUF -- cab
Changed _doAddUser, _doChangeUser to work with the public interface for
userfolders introduced in Zope2.5. Optional keyword arguments can now
be passed to _doAddUser and _doChangeUser.
PropertySource: Please note that createUser and updateUser, when called
from _doAddUser and _doChangeUser, will no longer be passed a REQUEST,
but a mapping with items from REQUEST updated with those from the
optional keyword arguments. -- pj
Fixed the problem with upgrading from 0.10.7 and below that didn't
account for existing XUF's not having a MessageDialog in their
contents. Now unless specificy replace it will use the MessageDialog
provided. Added how to do that to FAQ and README.Membership --cab
Made docLoginRedirect provide an absolute URL --bmh
MessageDialog in common no longer uses mangage_page_header and
mangage_page_footer v--cab
Changes for 0.10.8
Added the ability for members to change properties, and a default page
in the README.Membership to show how to do it --cab
MessageDialog is now an object in the ZODB that can be changed to fit
the site --cab
Now with 100% guaranteed race-condition-free UserCache goodness! Those
subclassing XUFUser, you will have to change your code. See User.py
for details. --mb
zodbBTreePropSource was returning None instead of the requested
default value, when called with (e.g.) someuser.getProperty('shoesize',13).
(Other property sources didn't have that bug.)
--davidc@debian.org
The tutorial loginform was wrong for Membership in README.Membership
Seems delProperty has never worked.. fixed --akm
Seems delProperty for pgPropSource has never worked.. fixed --akm
Fixed Basic Auth not auth problem. --akm
Fixed Basic Auth not cache problem. --akm
Fixed Cached Users bypassing some auth checks. --akm
Added usPropSource, which allows users to supply property methods TTW.
--bmh
Changes for 0.10.7
PropertyEditor had a typo in dtml and was casting int to None. --zxc
BasicAuth is now broken the other way, it'll allow any user to validate
with any password. --akm
Negative cache checking move was bogus. --akm
redirectToLogin didn't have a security declaration so 2.5.0 refused to
work in cookie mode *sigh* --akm
Fixed the 'None' object has no attribute 'load' setstate errors that
could crop up on propSources, and preemptively took care of the
authSources as well. Also fixed some of the weirder bugs relating to
user object acquisition context. --mb
Bug fixes from sf applied. --akm
Changes for 0.10.6
dummyZBabelTag used the python 2 re, which broke installations using
python 1.5 which still used the now deprecated regex, changed it to
catch the exception and use regex instead for python 1.5, else still
use re --cab
The redirectToLogin without Membership had a little logic problem where it
would basically garantee the existence of a query string, with at least a
lonely question mark even when there was no query string in the original
URL --rochael
smbAuthSource needed to cast NULL role properties to an empty list --akm
smbAuthSource had some dodgey zLOGing in it. --akm
smbAuthSource had some methods that should return [] instead of None. --akm
s/postgres/RADIUS/ in the radiusAuthSource DTML --akm
cookie_validate no longer pulls you from the cache if you're
logging in (which means your cookie wouldn't get set). --akm
Cookies are no longer expired if you're successfully authenticated but
merely unauthorized. --mb
Basic auth resynched with standard user folder, trying to fix
some basic auth issues. --akm.
Negative cache checking now performed outside of the two specific
validate methods. --akm.
A fairly innocuous print debug statement turned into a zLOG at error
level, removed --akm.
Clean up smbAuthSource log messages, and quieten. Only truly
exceptional cases are now logged above BLATHER. --mb
Changes for 0.10.5
Membership redirecting to login was still broken. It should be better
now (twice) --akm
logout() wasn't clearing the advanced cookie. --akm
Negative Cache Value wasn't being passed through to the XUF constructor. --akm
Log Users Out DTML code was broken, should work now. --akm
The User object now contains the authSource as well as the propSource,
making access to roles for custom User-objects possible. --dlk
Following akm's advice, fixed manage_beforeDelete to use two separate
try:except blocks to ensure that if cache-removal fails, deleting
the container.__allow_groups__ property is attempted. This should
fix the problem where deleted xuf instances remain as "ghost" products
causing interference with newer versions of xuf, and also fixes the
problem where deleting a xuf acl_users in a folder makes that folder
inaccessible. --dlk
Fixed cache_delete that was missing the "self" parameter in the method
defintion. --dlk
Fixed xcache_delete that was missing the "self" parameter in the method
definition --akm d8)
These previous two fix the problems with manage_beforeDelete, but, it
will stay the same for now --akm.
Fixed cache_deleteCookieCache that was missing the "self" parameter in
the method defintion. --dlk ;)
Changes for 0.10.4
The instructions for File Based Auth were incorrect in the UZG --akm
redirectToLogin was totally wrong for membership... --akm
docLogin was fixed for VHM use. --akm
Advanced Cookie Mode has changed so that it no longer sends the username
and password. Instead a hash is used as a key into a module level cache.
This should be 100% more secure than standard cookie mode, and removes
the stupid back doors I enabled in the previous version. This work was
based on conversations I had with Stuart Bishop (I basically lifted
the hashing scheme from GUF). This makes use of the Module level cache
code. --akm
There was a code cleanup and a slight reorganisation of some files. --akm
The main User Object has migrated to XUFUser and simarly with the
AnonUser. There is now an empty [Anon]User class that has XUFUser as
it's base. This allows people to create custom User Objects without
jumping through hoops (and simplifies maintaining patches) --akm
Cache Code has changed again. Now there is a module level cache, so
that auth data is shared between threads for a single XUF (thanks to
Stuart Bishop for an enlightening discussion on this and other issues,
and thanks to Chris McDonough for talking me through setting up module
level globals [and sending me some code to work from]) --akm
A Negative User Cache now exists. This is only generally useful for
use with remote auth sources where repeatedly trying to auth non-existant
users is very expensive (where they are authed at a higher level).
You can enable this on creation or from the parameters screen (positive
time in seconds enables). --akm
Domain checking code finally removed. --akm
zodbBTreePropSource changed to be friendlier about users that exist
in remote locations (i.e. aren't create as such through the ZMI). -- akm
Changed some 'print's in the code to use zLOG.LOG
instead. Files affected so far (more to follow): -- rochael
* exUserFolder.py
* basicMemberSource/basicMemberSource.py
* zodbBTreePropSource/zodbBTreePropSource.py
* zodbPropSource/zodbPropSource.py
Changed a couple things in smbAuthSource.py: -- rbanffy
* Method _authenticate_retry now logs several kinds of information
for debugging and diagnostics.
* Modified socket.error handling in _authenticate_retry: changed
"raise" to "return 0".
* Since this generated more problems (failed authentications) than
it solved (our impression it was not right not to return 0 in an
auth fail even due to a communications malfunction), we also
changed socket.error handling to retry no mather what errno tells
us (it said different things for the same problem under Windows
and Linux).
* In order to prevent infinite retries, changed retry handling a
bit. It now retries 3 times. Real-use data will tell us if we
should increase or not retries. To better convey the meaning of
the parameter, changed "retry_depth" to "retries". I strongly
advise the use of credential caching with smbAuthSource, tough, as
it reduces socket errors and load on the domain controllers.
Changes for 0.10.3.1
Readded support for I18N without ZBabel installation, somehow missed
during the transition to SF CVS.
Some text changes as well as an update to the dictionary while we're
at it. No functional changes for this release though.
Changes for 0.10.3
Missed a few LoginRequireds.
Fixed a bug with __allow_groups__ not being set after paste
(probably also not after import).
The sources are now sorted by name in the drop down box..
a BTree version of zodbAuthSource
a BTree version of zodbPropSource
These aren't really all that different to the originals that were
provided by Alex, but, they use BTrees instead of PersistentMappings,
and try to avoid various persistence problems associated with dicts.
Both versions will continue to be supported.
Patches from SF applied.
Advanced Cookie Mode added.
This mode adds a rotor cipher around the cookie. A secret is provided
in order to encode the cookie. The username and password are placed
within a small class which is pickled and then encrypted and then
base64 encoded for transport. There is also a timestamp inside the cookie,
so the ultra-paranoid of you can rotate the cookie based on the timestamp
inside.
Abstracted out the setting and decoding of cookies.
Changes for 0.10.2
all raise 'LoginRequired' <- raise 'Unauthorized'
Raising unauthorizes breaks a million things. CMF people can just
put up with configuring their portal properly.
Radius resynced with version from sourceforge.
manage_tabs redone to be ZBabel'd and to look like standard tabs.
German Language added to the ZBabel dictionary.
Changes for 0.10.1
all raise 'LoginRequired' -> raise 'Unauthorized'
Bug in etcAuthSource listUsers fixed,
and cryptPassword also fixed to get the actual salt.
Zope 2.4.3 has dicked with security settings again.. I've had a round
of permission whacking.
Buggy handling of empty role lists was fixed.
Change to smbAuthSource to use string.lower on usernames for
python 1.5.2 compatibility?
Changes for 0.10.0
Added explicit roles for manage_editUser and friends, to allow
the "Manage users" permission to be useful to non-Manager Users.
Thanks to Heimo Laukkanen <huima@fountainpark.org> for reporting this
one.
zodbAuthSource made more persistent <alex@quad.com.ar>
zodbPropSource was blowing when deleting temporary properties.
XUF is now ZBabel'd which means you can view XUF in different languages
for logging in and installation, if your browser locale is set up.
You will need the latest ZBabel installed. The translation file is in the
I18N directory.
Import this (using Import/Export in ZODB) at the same level as your
ZBabelTower, and then import it from ZBabel. If you have ZBabel installed,
but, your application can't find a ZBabelTower, because of a bug in the
current dtml-fish tag, you might experience some problems. This ZBabel
bug should be fixed sometime soon.
You do not need ZBabel installed to run XUF, XUF installs a dummy
interface for ZBabel so that XUF can continue to run (sorry folks it
defaults to Australian English).
getUserNames() was returning the wrong stuff (notably affected TheJester's
WorkOrders Product)
There is a now an 'Advanced Postgres' Auth Source that uses a seperate
Roles table and a 'more relational' layout. The schema is with the
auth source in pgAuthSourceAlt. Contributed by
Adam Manock <abmanock@earthlink.net>
If you had a membership source and had specified a login page, XUF was
still using the stock docLogin instead of the membership specified page
(for redirectToLogin, exceptions still raise the docLogin).
I changed the icon to something a *little* less hideous
Leonardo Rochael Almeida <leo@hiper.com.br> made the following changes
to smbAuthSource
* Added a 'winsserver' constructor parameter and a '_winsserver'
instance variable to the 'smbAuthSource' class. This variable should
be the empty string, meaning that the authenticaton host will be
looked up by broadcast, or an IP address string pointing to a WINS
server.
* Modified the dtml templates to ask for the above mentioned WINS
server (and also to replace 'Add' with 'Change' in
'manage_editsmbAuthSourceForm').
* Refactored the smbAuthSource class to isolate all smb interaction
inside well defined methods.
Changes for 0.9.0
Messages are now sent back to the docLogin form. There's a file called
LoginRequiredMessages.py where the messages are kept for now (it might
end up a run-time configurable thing later).
There's a new docLogin.dtml file on disk that shows how to use the new
messages. Because docLogin is in the ZODB this won't be automatically
upgraded.
Idle Session Timeouts are in (this is the reason for the minor bump).
If you flick the switch, then users are forced back to the login form
(with a message saying their session timed out), when they're removed
from the cache.
I made some adjustments to the tabs on the management interface because
they were too big, and I cleaned it up a bit for times when they run
together.
The internal API was inconsistent, so that's been updated.
AuthSources no longer need to provide getUsers(), it was never
being called anyway since exUserFolder built it's own.
listUsers now returns the same data as listOneUser, this is used in
other places as if it were a list of listOneUser calls.
Fixed pgAuthSource to deal with NULL rather than empty roles
columns (legacy columns).
Changed Home Directory creation to use copy & paste functions to
copy the skeleton data.
Changes for 0.8.5
I forgot to update the schema file for userproperties to reflect
the temporary properties flag.
Checks for existing cache weren't being performed before removing users
from it, when their data was updated.
Reversed the order for checking in cookie_validate, to allow logging
in as a new user, when session tracking was on. Also now you can
login as a different user, without logging out first, which might
be useful to some people.
etcAuthSource now looks for the correct salt from the file for
encrypting the user supplied password
Changes for 0.8.4
Activating Session Tracking and then adding a new user when there
were none in the XUF was broken.
Changes for 0.8.3
The idle users are flushed from the cache when you ask for the list
of cache users (since it's iterating over the whole list anyway). So
you can manually clear your cache by looking at the Cache Stats page.
If you display the list of logged in users on your site, then your cache
will be flushed for you automagically.
Allowed a destination to be sent to redirectToLogin to allow you to
manually override the destination after logging in.
Added in a __setstate__ for pgPropSource to deal with new ZSQL Methods
being added.
Changes for 0.8.2
A number of bugs related to temp properties fixed in pgPropSource
FTP Access to folders protected with cookie_mode has been fixed, it
now reverts to std_auth (which handles the FTP connection fine), since
FTP auths are handled by getting a "Basic" auth tag coming through, which
should never happen in cookie mode.
This has the knock-on effect of authenticating users that auth from a
higher acl_users that doesn't use cookies, 'more' correctly now. Which is
if you have a user defined above, and in XUF and the XUF user has less
permissions, it'll 401 you if you don't have permissions locally
(which is the correct behaviour). This bit me in the arse when I changed it,
and I'm still leaving it this way. d8)
Users are now flushed from the cache when you edit them (in case you changed
roles), so that new roles should take effect immediately.
The credential cache now uses the (Zope) builtin BTree Module for caching
rather than the AVL Tree implementation. There was a nasty issue with users
appearing multiple times in the AVL Tree which sucked.
There is a report of the Radius Auth Source being broken (most likely
by me), if your radius source stops working, you can try copying the
py-radius.py file from sourceforge over the top of radius.py. If someone
gives me a traceback, I can fix it. I don't seem to be having problems,
but, I don't have a full time RADIUS source either.
Changes for 0.8.1
A bug in _doAddUser was fixed
A bug in the User Object unconditionally calling the prop source was fixed.
Changes for 0.8.0
Experimental "Session Tracking" added (why is it called that? we don't really
track anything, just associate arbitrary data with anonymous users).
This relies on the credential cache being active. Your session will
automatically expire when the anonymous user is so idle that they are
expired from the cache. This is not currently acceptable (to me), but,
it might be to other people, I await feedback on how sessions should expire
gracefully.
Updated the README.txt file to point at the UZG and to explain the
version numbering system.
All this time you couldn't delete properties from a user... who knew?
It's fixed now.
Temporary properties now available, you can setTempProperty() on a
user object, and also flushTempProperties() on a user object.
Temporary properties are accessed like normal properties, and can be
deleted in the same way. flushTempProperties is there to do a quick
flush of all the crap you might have inserted (useful for sessions).
If your user is flushed from the cache, then all temp properties will
also be removed at that point.
Propsource providers should look at the new temp properties stuff and
update accordingly.
Alex provided a whole heap of patches to make basicMembership more usable,
well make it actually work.
Matt Behrens supplied patches to prevent null logins and to allow case
insensitive logins for smbAuthSource
Added a basic FAQ.
Changes for 0.7.10
Active Users type functionality was added. The new function is called
getUserCacheUsers(). It returns a list of dicts;
{'username': theusername, 'lastAccessed': float_value}
lastAccessed represents the last time the user touched something.
The Cache Stats page shows an example usage showing idle time (very cool
I think :-)
The logout method was not correctly removing users from the cache,
although the cookie was removed, so logins were still enforced. I'm not
sure of any side-effects related to it, but,
Some permissions were a little too liberal, including allowing arbitrary
users to set and get Properties on the acl_users folder.
Copy/Paste support for pasting exUserFolders into the root was added.
I'm not sure I like the way this is done. I haven't found any side effects
so far, but, just be wary. Adding an exUserFolder to the root becomes
semi-trivial now. Create one in a sub-folder. Login as the emergency user.
CUT the exUserFolder. Delete the standard acl_users folder. Paste exUserFolder.
You should be away. At least it worked fine for me... YMMV
_doChangeUser and _doDelUsers added so users can be altered and deleted
like for Standard UserFolder.
_createInitialUser added so there should always be your initUser (hopefully)
when you create your exUserFolder.
Emergency User checking brought into line with Standard Folder
__creatable_by_emergency_user_ added and returns 1 to explicitly allow this.
Unenlightened Zopistas Guide updated to have a 'Recipe' like section.
Currently contains a section about adding exUserFolders from python.
Changes for 0.7.9
RADIUS authSource had a problem with non-integers being extracted from
REQUEST (I wish someone at DC would fix this already). I worked around
this problem
Default port for RADIUS is now 1812 in line with the IANA sanctioned list.
Unenlightened Zopistas Guide to exUserFolder version 0.0 included,
covers installation and authentication sources, and the most common
configuration mistake (or misunderstanding).
I almost released with the daggy management screens all Purple or SkyBlue,
so consider yoursevles lucky. This would have been the "Blue" release.
Changes for 0.7.8
zodbPropSource had a bug that must have been there since 0.0.0 where
_p_changed wasn't being called on create, update, or delete user.
Thanks to Bouke Scheurwater for spotting that one.
Alex provided a number of patched to fix a whole bunch of goofy stuff
with Basic Member Source that was stupidly wrong.
Matt Behrens provided a patch to allow emergency user to own exUserFolders
and some of the sources. I've grudgingly updated all the sources to allow
this. It's just a hey nonny nonny to people using it as a root authenticator
now.
Matt Behrens also provided a patch to fix 'broken pipe' problems with
smbAuthSource.
pySMB is now at 0.2 for smbAuthSource WARNING: This will try to use DES
encrypted passwords. Apparently it should be ok if your server doesn't want
them. However if it breaks, unpack the pySMB distribution in the
smbAuthSource directory, there are registry examples there to turn
it off. It unfortunately needs the mxCrypto tools for encrypted passwords
to work. When I've got a bit more time, I'll see if I can make it use
crypt or fcrypt if available instead.
Explicit checks for the emergency user were placed into the cookie_validate
routines. I suspect this may have been the cause of some grief with people
doing weird things like trying to make it the root auth folder.
Changes for 0.7.7
Some Auth sources had problems coping with no roles being selected when
a user was created from the management interface, the stock ones were fixed.
I screwed up some of the DTML, and forgot to change the loading of two of
the methods from the dtml directory.
NO MORE TRACEBACKS ON LOGIN FORMS, there is a little redirector dtml file
dtml/docLoginRedirect that redirects to acl_users/docLogin with destination
set to take them back to where they were going. If you have a custom loginPage
change the redirector dtml to point to your new page.
standard_html swapped for manage_page on Management Pages. Hopefully
this doesn't break someone with an old copy of Zope.
Credential Caching is now available by default for all Authentication Sources,
upgrading installs will get this defaulted to 0 for no caching. You can alter
the cache level from the Parameters Tab. Authors of external sources should
remove any internal auth caching they're doing, and allow the user to decide
how long to cache the credentials for.
Changes for 0.7.6
smbAuthSource included. Doesn't require any external libraries, or compiling.
Uses pySMB from Micheal Teo <michaelteo@bigfoot.com>
Changes for 0.7.5
The Management Interface now batches the user list by 10. This isn't
configurable at the moment (just change the dtml).
The code was re-organised slightly, with all the DTML moving into its
own directory for core.
radiusAuthSource added, but, is so far untested. It is a direct port of
ZRadius for GUF, but, I haven't had a chance to setup a RADIUS server to
test it out.
You can add properties to a user from the management interface.
List Properties on users can be added and edited, if I can work out a decent
way to edit Dicts/Mappings, I'll add that feature in.
This paves the way for defining a set of properties in the Membership
source, so it can create a Signup and Edit page for you automatically.
You will also be able to specify which properties the user can edit, or
roles required to edit a property, this will be in a later release though.
pgPropSource was updated to take into account non-scalar types, and now
pickles all data going into the database, this means ints will stay as ints,
et al.
There is code in there to cope with older properties coming out as strings.
The Schema remains the same.
Changes for 0.7.2
Changes to make it work with older version of python
Some minor bug fixes for membership.
Changes for 0.7.1
DTML Change for cmfPropSource
Changes for 0.7.0
exUserFolder was a little too liberal in removing its cruft, this is now
fixed.
cmfPropSource was provided by Alan Runyan which is a layer around the CMF
property stuff. It's conditionally imported, so if you don't have CMF
installed you don't need to worry that'll it'll break.
Property Sources are optional, and there is a NULL Property Source for this
purpose.
Membership hooks, and a rough start at membership (basicMemberSource),
which has some usable functionality (you MUST read README.Membership before
using this).
Membership Sources are optional and there is a NULL Membership Source for
this purpose.
Changes for 0.6.2
exUserFolder was leaving cruft around when it was being deleted from
Folders. The cruft should now be obliterated if you delete an exUserFolder.
Changes for 0.6.1
Ownership tab enabled, for those sick monkeys that want to use it as a root
Folder (there are some).
fcrypt got the __init__.py that was missing from the 0.6.0 release
zodbAuthSource updated to pull in fcrypt if crypt was missing.
Changes for 0.6.0
Updated for 2.4.1 / Python 2.1
Bug in pgPropSource not deleting users from the property cache fixed.
Bug with Local Roles not getting what it expected fixed.
Alex Verstraeten provided zodbAuthSource, there's a README.zodbAuthSource,
and the same README inside the zodbAuthSource directory.
fcrypt is now included and used if crypt cannot be imported. More information
on fcrypt can be found at http://home.clear.net.nz/pages/c.evans/sw/. This
should help particularly Windows users a lot.
Rudimentary API doc included.
Changes for 0.5.0
A serious bug in zodbPropSource was fixed.
There is now the option of providing a 'Remote Auth' function for
validating. This allows things like IMAP/LDAP auth sources to do their
authentication, since they don't return passwords you can use in general.
There's already a 3rd Party solution that provides IMAP/POP3 authentication,
using the new API.
Changes for 0.4.6
Minor dtml hacks
Changes for 0.4.5
Hooks for 'editing' Authentication and Property Sources were added, along
with the relevant methods in each of the sources.
The management interfaces got a little overhaul, just to make them
a little different (yes I know everything I do looks the same). The two
I didn't want to mess with still have the acquired management interfaces.
A fix for the ZODB Property Source which was missing a few methods.
Changes for 0.4.0
Based on an idea from Martin von Loewis, I added in support for defining
roles for etcAuthSource. This basically uses the current Prop source to
store a 'roles' property. The default role is still there as well for
those of you who might be using it.
Changes for 0.3.0
Adrien Hernot noticed that properties for new users using zodbPropSource
were causing havoc, and that the version.txt file was completely wrong.
Andreas also noticed the version.txt was wrong.
I've been bugged enough by the pair of them to change the single +=
into 1.5.2 compliant syntax.
I don't make any claims about it working under 1.5.2 though.
Changes for 0.2.0
Even more embarassment...
Andreas Heckel provided fixes for some stupid things I left out including;
o Fixing the way I was handling multiple roles coming out of the database
o The wrong icon in the user display
o Alerting me to the fact that pgPropSource didn't actually have a
deleteUsers hook
o Providing a schema for automatically deleting properties in postgres
if you delete a user from the auth source (you have to be using both
pg sources for this to work, and they'd have to be in the same database)
I've put Andreas schema into the distribution, if you want to use
exUserFolder as a straight pgUserFolder, you'll also need to edit
exUserFolder.py and comment out the line indicated in deleteUsers()
Changes for 0.1.0
Pretty embarassing really.
M. Adam Kendall (DaJoker) found some stupid things in the 0.0.0 release
including the fact you couldn't edit user properties, or update them,
or actually change a user in anyway.
I also discovered I was resetting the password to empty if you left it
empty..

View File

@ -1,4 +0,0 @@
import pass_crypt
import pass_md5
import pass_sha
import pass_plain

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,35 +0,0 @@
2001-05-05 Carey Evans <careye@spamcop.net>
* fcrypt.py: Add module doc string for pydoc, and other globals
for pydoc as well. Add __all__ for Python 2.1, and add
underscores to the front of private variables and functions.
(_set_key): Remove overly clever copying of globals into default
parameters, explicitly copying _shift2 and _skb before the loop.
(_body): Copy _SPtrans explicitly, as above. Remove CR_ENCRYPT
inline function, and reroll unrolled loop using the contents of
this function. Result: more readable code, and a 400% speedup!
(crypt): Add doc string for pydoc and doctest.
(_test): New function for doctest.
* setup.py: Add fields for PKG-INFO metadata.
* README: Add URL of distutils installation manual.
* LICENSE: Add note about license on fcrypt.py being the union of
my license on the Python code and Eric Young's on the original C.
2001-03-24 Carey Evans <careye@spamcop.net>
* setup.py: Move license to separate file. Change email address
to SpamCop forwardder. Update version to 1.1.
* fcrypt.py: Update license text and email address.
(crypt): Fix bug where passwords longer than eight characters were
not truncated.
* README: Update crypt module URL. Remove license text, and add
pointer to LICENSE file. Update email address.
* MANIFEST.in: Add LICENSE, ChangeLog and MANIFEST.in.
* LICENSE: New file.

View File

@ -1,77 +0,0 @@
fcrypt.py copyrights and license
--------------------------------
The Python code by Carey Evans has the following license, which is the
original Python license with the serial numbers filed off, and the
restrictions on advertising removed.
Copyright (C) 2001, 2001 Carey Evans <careye@spamcop.net>
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation.
CAREY EVANS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
EVENT SHALL CAREY EVANS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
The original C code on which this module was based has the following
more restrictive license, so the source for fcrypt.py should be
considered to be covered by the union of my license and Eric Young's.
This library is free for commercial and non-commercial use as long as
the following conditions are aheared to. The following conditions
apply to all code found in this distribution, be it the RC4, RSA,
lhash, DES, etc., code; not just the SSL code. The SSL documentation
included with this distribution is covered by the same copyright terms
except that the holder is Tim Hudson (tjh@mincom.oz.au).
Copyright remains Eric Young's, and as such any Copyright notices in
the code are not to be removed.
If this package is used in a product, Eric Young should be given attribution
as the author of the parts of the library used.
This can be in the form of a textual message at program startup or
in documentation (online or textual) provided with the package.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
"This product includes cryptographic software written by
Eric Young (eay@mincom.oz.au)"
The word 'cryptographic' can be left out if the rouines from the library
being used are not cryptographic related :-).
4. If you include any Windows specific code (or a derivative thereof) from
the apps directory (application code) you must include an acknowledgement:
"This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
The licence and distribution terms for any publically available version or
derivative of this code cannot be changed. i.e. this code cannot simply be
copied and put under another distribution licence
[including the GNU Public Licence.]

View File

@ -1 +0,0 @@
include LICENSE ChangeLog MANIFEST.in

View File

@ -1,13 +0,0 @@
Metadata-Version: 1.0
Name: fcrypt
Version: 1.2
Summary: The Unix password crypt function.
Home-page: http://home.clear.net.nz/pages/c.evans/sw/
Author: Carey Evans
Author-email: careye@spamcop.net
License: BSD
Description: A pure Python implementation of the Unix DES password crypt function,
based on Eric Young's fcrypt.c. It works with any version of Python
from version 1.5 or higher, and because it's pure Python it doesn't
need a C compiler to install it.
Platform: UNKNOWN

View File

@ -1,33 +0,0 @@
fcrypt.py
---------
This is a pure Python implementation of the Unix DES password crypt
function. It was ported from C code by Eric Young (eay@mincom.oz.au).
See the file LICENSE for copyright and license details.
This module is packaged with Distutils. If you have this installed,
or it came with your version of Python, you can install it by typing:
python setup.py install
If not, you can just copy `fcrypt.py' into a directory on your Python
library path, or into the same directory as the program that wants to
use it.
For more information, see the documentation for Python's built-in
crypt module at:
http://www.python.org/doc/current/lib/module-crypt.html
Eric Young's fcrypt.c is available from:
ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/
For more Distutils information, see:
http://www.python.org/doc/current/inst/inst.html
http://www.python.org/sigs/distutils-sig/
--
Carey Evans <careye@spamcop.net>
5 May 2001

View File

@ -1 +0,0 @@
import fcrypt

View File

@ -1,602 +0,0 @@
# fcrypt.py
"""Unix crypt(3) password hash algorithm.
This is a port to Python of the standard Unix password crypt function.
It's a single self-contained source file that works with any version
of Python from version 1.5 or higher. The code is based on Eric
Young's optimised crypt in C.
Python fcrypt is intended for users whose Python installation has not
had the crypt module enabled, or whose C library doesn't include the
crypt function. See the documentation for the Python crypt module for
more information:
http://www.python.org/doc/current/lib/module-crypt.html
The crypt() function is a one-way hash function, intended to hide a
password such that the only way to find out the original password is
to guess values until you get a match. If you need to encrypt and
decrypt data, this is not the module for you.
There are at least two packages providing Python cryptography support:
M2Crypto at <http://www.pobox.org.sg/home/ngps/m2/>, and amkCrypto at
<http://www.amk.ca/python/code/crypto.html>.
Functions:
crypt() -- return hashed password
"""
__author__ = 'Carey Evans <careye@spamcop.net>'
__version__ = '1.2'
__date__ = '6 May 2001'
__credits__ = '''michal j wallace for inspiring me to write this.
Eric Young for the C code this module was copied from.'''
__all__ = ['crypt']
# Copyright (C) 2000, 2001 Carey Evans <careye@spamcop.net>
#
# Permission to use, copy, modify, and distribute this software and
# its documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and
# that both that copyright notice and this permission notice appear in
# supporting documentation.
#
# CAREY EVANS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
# EVENT SHALL CAREY EVANS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
# Based on C code by Eric Young (eay@mincom.oz.au), which has the
# following copyright. Especially note condition 3, which imposes
# extra restrictions on top of the standard Python license used above.
#
# The fcrypt.c source is available from:
# ftp://ftp.psy.uq.oz.au/pub/Crypto/DES/
# ----- BEGIN fcrypt.c LICENSE -----
#
# This library is free for commercial and non-commercial use as long as
# the following conditions are aheared to. The following conditions
# apply to all code found in this distribution, be it the RC4, RSA,
# lhash, DES, etc., code; not just the SSL code. The SSL documentation
# included with this distribution is covered by the same copyright terms
# except that the holder is Tim Hudson (tjh@mincom.oz.au).
#
# Copyright remains Eric Young's, and as such any Copyright notices in
# the code are not to be removed.
# If this package is used in a product, Eric Young should be given attribution
# as the author of the parts of the library used.
# This can be in the form of a textual message at program startup or
# in documentation (online or textual) provided with the package.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
# must display the following acknowledgement:
# "This product includes cryptographic software written by
# Eric Young (eay@mincom.oz.au)"
# The word 'cryptographic' can be left out if the rouines from the library
# being used are not cryptographic related :-).
# 4. If you include any Windows specific code (or a derivative thereof) from
# the apps directory (application code) you must include an acknowledgement:
# "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"
#
# THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# The licence and distribution terms for any publically available version or
# derivative of this code cannot be changed. i.e. this code cannot simply be
# copied and put under another distribution licence
# [including the GNU Public Licence.]
#
# ----- END fcrypt.c LICENSE -----
import string, struct
_ITERATIONS = 16
_SPtrans = (
# nibble 0
[ 0x00820200, 0x00020000, 0x80800000, 0x80820200,
0x00800000, 0x80020200, 0x80020000, 0x80800000,
0x80020200, 0x00820200, 0x00820000, 0x80000200,
0x80800200, 0x00800000, 0x00000000, 0x80020000,
0x00020000, 0x80000000, 0x00800200, 0x00020200,
0x80820200, 0x00820000, 0x80000200, 0x00800200,
0x80000000, 0x00000200, 0x00020200, 0x80820000,
0x00000200, 0x80800200, 0x80820000, 0x00000000,
0x00000000, 0x80820200, 0x00800200, 0x80020000,
0x00820200, 0x00020000, 0x80000200, 0x00800200,
0x80820000, 0x00000200, 0x00020200, 0x80800000,
0x80020200, 0x80000000, 0x80800000, 0x00820000,
0x80820200, 0x00020200, 0x00820000, 0x80800200,
0x00800000, 0x80000200, 0x80020000, 0x00000000,
0x00020000, 0x00800000, 0x80800200, 0x00820200,
0x80000000, 0x80820000, 0x00000200, 0x80020200 ],
# nibble 1
[ 0x10042004, 0x00000000, 0x00042000, 0x10040000,
0x10000004, 0x00002004, 0x10002000, 0x00042000,
0x00002000, 0x10040004, 0x00000004, 0x10002000,
0x00040004, 0x10042000, 0x10040000, 0x00000004,
0x00040000, 0x10002004, 0x10040004, 0x00002000,
0x00042004, 0x10000000, 0x00000000, 0x00040004,
0x10002004, 0x00042004, 0x10042000, 0x10000004,
0x10000000, 0x00040000, 0x00002004, 0x10042004,
0x00040004, 0x10042000, 0x10002000, 0x00042004,
0x10042004, 0x00040004, 0x10000004, 0x00000000,
0x10000000, 0x00002004, 0x00040000, 0x10040004,
0x00002000, 0x10000000, 0x00042004, 0x10002004,
0x10042000, 0x00002000, 0x00000000, 0x10000004,
0x00000004, 0x10042004, 0x00042000, 0x10040000,
0x10040004, 0x00040000, 0x00002004, 0x10002000,
0x10002004, 0x00000004, 0x10040000, 0x00042000 ],
# nibble 2
[ 0x41000000, 0x01010040, 0x00000040, 0x41000040,
0x40010000, 0x01000000, 0x41000040, 0x00010040,
0x01000040, 0x00010000, 0x01010000, 0x40000000,
0x41010040, 0x40000040, 0x40000000, 0x41010000,
0x00000000, 0x40010000, 0x01010040, 0x00000040,
0x40000040, 0x41010040, 0x00010000, 0x41000000,
0x41010000, 0x01000040, 0x40010040, 0x01010000,
0x00010040, 0x00000000, 0x01000000, 0x40010040,
0x01010040, 0x00000040, 0x40000000, 0x00010000,
0x40000040, 0x40010000, 0x01010000, 0x41000040,
0x00000000, 0x01010040, 0x00010040, 0x41010000,
0x40010000, 0x01000000, 0x41010040, 0x40000000,
0x40010040, 0x41000000, 0x01000000, 0x41010040,
0x00010000, 0x01000040, 0x41000040, 0x00010040,
0x01000040, 0x00000000, 0x41010000, 0x40000040,
0x41000000, 0x40010040, 0x00000040, 0x01010000 ],
# nibble 3
[ 0x00100402, 0x04000400, 0x00000002, 0x04100402,
0x00000000, 0x04100000, 0x04000402, 0x00100002,
0x04100400, 0x04000002, 0x04000000, 0x00000402,
0x04000002, 0x00100402, 0x00100000, 0x04000000,
0x04100002, 0x00100400, 0x00000400, 0x00000002,
0x00100400, 0x04000402, 0x04100000, 0x00000400,
0x00000402, 0x00000000, 0x00100002, 0x04100400,
0x04000400, 0x04100002, 0x04100402, 0x00100000,
0x04100002, 0x00000402, 0x00100000, 0x04000002,
0x00100400, 0x04000400, 0x00000002, 0x04100000,
0x04000402, 0x00000000, 0x00000400, 0x00100002,
0x00000000, 0x04100002, 0x04100400, 0x00000400,
0x04000000, 0x04100402, 0x00100402, 0x00100000,
0x04100402, 0x00000002, 0x04000400, 0x00100402,
0x00100002, 0x00100400, 0x04100000, 0x04000402,
0x00000402, 0x04000000, 0x04000002, 0x04100400 ],
# nibble 4
[ 0x02000000, 0x00004000, 0x00000100, 0x02004108,
0x02004008, 0x02000100, 0x00004108, 0x02004000,
0x00004000, 0x00000008, 0x02000008, 0x00004100,
0x02000108, 0x02004008, 0x02004100, 0x00000000,
0x00004100, 0x02000000, 0x00004008, 0x00000108,
0x02000100, 0x00004108, 0x00000000, 0x02000008,
0x00000008, 0x02000108, 0x02004108, 0x00004008,
0x02004000, 0x00000100, 0x00000108, 0x02004100,
0x02004100, 0x02000108, 0x00004008, 0x02004000,
0x00004000, 0x00000008, 0x02000008, 0x02000100,
0x02000000, 0x00004100, 0x02004108, 0x00000000,
0x00004108, 0x02000000, 0x00000100, 0x00004008,
0x02000108, 0x00000100, 0x00000000, 0x02004108,
0x02004008, 0x02004100, 0x00000108, 0x00004000,
0x00004100, 0x02004008, 0x02000100, 0x00000108,
0x00000008, 0x00004108, 0x02004000, 0x02000008 ],
# nibble 5
[ 0x20000010, 0x00080010, 0x00000000, 0x20080800,
0x00080010, 0x00000800, 0x20000810, 0x00080000,
0x00000810, 0x20080810, 0x00080800, 0x20000000,
0x20000800, 0x20000010, 0x20080000, 0x00080810,
0x00080000, 0x20000810, 0x20080010, 0x00000000,
0x00000800, 0x00000010, 0x20080800, 0x20080010,
0x20080810, 0x20080000, 0x20000000, 0x00000810,
0x00000010, 0x00080800, 0x00080810, 0x20000800,
0x00000810, 0x20000000, 0x20000800, 0x00080810,
0x20080800, 0x00080010, 0x00000000, 0x20000800,
0x20000000, 0x00000800, 0x20080010, 0x00080000,
0x00080010, 0x20080810, 0x00080800, 0x00000010,
0x20080810, 0x00080800, 0x00080000, 0x20000810,
0x20000010, 0x20080000, 0x00080810, 0x00000000,
0x00000800, 0x20000010, 0x20000810, 0x20080800,
0x20080000, 0x00000810, 0x00000010, 0x20080010 ],
# nibble 6
[ 0x00001000, 0x00000080, 0x00400080, 0x00400001,
0x00401081, 0x00001001, 0x00001080, 0x00000000,
0x00400000, 0x00400081, 0x00000081, 0x00401000,
0x00000001, 0x00401080, 0x00401000, 0x00000081,
0x00400081, 0x00001000, 0x00001001, 0x00401081,
0x00000000, 0x00400080, 0x00400001, 0x00001080,
0x00401001, 0x00001081, 0x00401080, 0x00000001,
0x00001081, 0x00401001, 0x00000080, 0x00400000,
0x00001081, 0x00401000, 0x00401001, 0x00000081,
0x00001000, 0x00000080, 0x00400000, 0x00401001,
0x00400081, 0x00001081, 0x00001080, 0x00000000,
0x00000080, 0x00400001, 0x00000001, 0x00400080,
0x00000000, 0x00400081, 0x00400080, 0x00001080,
0x00000081, 0x00001000, 0x00401081, 0x00400000,
0x00401080, 0x00000001, 0x00001001, 0x00401081,
0x00400001, 0x00401080, 0x00401000, 0x00001001 ],
# nibble 7
[ 0x08200020, 0x08208000, 0x00008020, 0x00000000,
0x08008000, 0x00200020, 0x08200000, 0x08208020,
0x00000020, 0x08000000, 0x00208000, 0x00008020,
0x00208020, 0x08008020, 0x08000020, 0x08200000,
0x00008000, 0x00208020, 0x00200020, 0x08008000,
0x08208020, 0x08000020, 0x00000000, 0x00208000,
0x08000000, 0x00200000, 0x08008020, 0x08200020,
0x00200000, 0x00008000, 0x08208000, 0x00000020,
0x00200000, 0x00008000, 0x08000020, 0x08208020,
0x00008020, 0x08000000, 0x00000000, 0x00208000,
0x08200020, 0x08008020, 0x08008000, 0x00200020,
0x08208000, 0x00000020, 0x00200020, 0x08008000,
0x08208020, 0x00200000, 0x08200000, 0x08000020,
0x00208000, 0x00008020, 0x08008020, 0x08200000,
0x00000020, 0x08208000, 0x00208020, 0x00000000,
0x08000000, 0x08200020, 0x00008000, 0x00208020 ] )
_skb = (
# for C bits (numbered as per FIPS 46) 1 2 3 4 5 6
[ 0x00000000, 0x00000010, 0x20000000, 0x20000010,
0x00010000, 0x00010010, 0x20010000, 0x20010010,
0x00000800, 0x00000810, 0x20000800, 0x20000810,
0x00010800, 0x00010810, 0x20010800, 0x20010810,
0x00000020, 0x00000030, 0x20000020, 0x20000030,
0x00010020, 0x00010030, 0x20010020, 0x20010030,
0x00000820, 0x00000830, 0x20000820, 0x20000830,
0x00010820, 0x00010830, 0x20010820, 0x20010830,
0x00080000, 0x00080010, 0x20080000, 0x20080010,
0x00090000, 0x00090010, 0x20090000, 0x20090010,
0x00080800, 0x00080810, 0x20080800, 0x20080810,
0x00090800, 0x00090810, 0x20090800, 0x20090810,
0x00080020, 0x00080030, 0x20080020, 0x20080030,
0x00090020, 0x00090030, 0x20090020, 0x20090030,
0x00080820, 0x00080830, 0x20080820, 0x20080830,
0x00090820, 0x00090830, 0x20090820, 0x20090830 ],
# for C bits (numbered as per FIPS 46) 7 8 10 11 12 13
[ 0x00000000, 0x02000000, 0x00002000, 0x02002000,
0x00200000, 0x02200000, 0x00202000, 0x02202000,
0x00000004, 0x02000004, 0x00002004, 0x02002004,
0x00200004, 0x02200004, 0x00202004, 0x02202004,
0x00000400, 0x02000400, 0x00002400, 0x02002400,
0x00200400, 0x02200400, 0x00202400, 0x02202400,
0x00000404, 0x02000404, 0x00002404, 0x02002404,
0x00200404, 0x02200404, 0x00202404, 0x02202404,
0x10000000, 0x12000000, 0x10002000, 0x12002000,
0x10200000, 0x12200000, 0x10202000, 0x12202000,
0x10000004, 0x12000004, 0x10002004, 0x12002004,
0x10200004, 0x12200004, 0x10202004, 0x12202004,
0x10000400, 0x12000400, 0x10002400, 0x12002400,
0x10200400, 0x12200400, 0x10202400, 0x12202400,
0x10000404, 0x12000404, 0x10002404, 0x12002404,
0x10200404, 0x12200404, 0x10202404, 0x12202404 ],
# for C bits (numbered as per FIPS 46) 14 15 16 17 19 20
[ 0x00000000, 0x00000001, 0x00040000, 0x00040001,
0x01000000, 0x01000001, 0x01040000, 0x01040001,
0x00000002, 0x00000003, 0x00040002, 0x00040003,
0x01000002, 0x01000003, 0x01040002, 0x01040003,
0x00000200, 0x00000201, 0x00040200, 0x00040201,
0x01000200, 0x01000201, 0x01040200, 0x01040201,
0x00000202, 0x00000203, 0x00040202, 0x00040203,
0x01000202, 0x01000203, 0x01040202, 0x01040203,
0x08000000, 0x08000001, 0x08040000, 0x08040001,
0x09000000, 0x09000001, 0x09040000, 0x09040001,
0x08000002, 0x08000003, 0x08040002, 0x08040003,
0x09000002, 0x09000003, 0x09040002, 0x09040003,
0x08000200, 0x08000201, 0x08040200, 0x08040201,
0x09000200, 0x09000201, 0x09040200, 0x09040201,
0x08000202, 0x08000203, 0x08040202, 0x08040203,
0x09000202, 0x09000203, 0x09040202, 0x09040203 ],
# for C bits (numbered as per FIPS 46) 21 23 24 26 27 28
[ 0x00000000, 0x00100000, 0x00000100, 0x00100100,
0x00000008, 0x00100008, 0x00000108, 0x00100108,
0x00001000, 0x00101000, 0x00001100, 0x00101100,
0x00001008, 0x00101008, 0x00001108, 0x00101108,
0x04000000, 0x04100000, 0x04000100, 0x04100100,
0x04000008, 0x04100008, 0x04000108, 0x04100108,
0x04001000, 0x04101000, 0x04001100, 0x04101100,
0x04001008, 0x04101008, 0x04001108, 0x04101108,
0x00020000, 0x00120000, 0x00020100, 0x00120100,
0x00020008, 0x00120008, 0x00020108, 0x00120108,
0x00021000, 0x00121000, 0x00021100, 0x00121100,
0x00021008, 0x00121008, 0x00021108, 0x00121108,
0x04020000, 0x04120000, 0x04020100, 0x04120100,
0x04020008, 0x04120008, 0x04020108, 0x04120108,
0x04021000, 0x04121000, 0x04021100, 0x04121100,
0x04021008, 0x04121008, 0x04021108, 0x04121108 ],
# for D bits (numbered as per FIPS 46) 1 2 3 4 5 6
[ 0x00000000, 0x10000000, 0x00010000, 0x10010000,
0x00000004, 0x10000004, 0x00010004, 0x10010004,
0x20000000, 0x30000000, 0x20010000, 0x30010000,
0x20000004, 0x30000004, 0x20010004, 0x30010004,
0x00100000, 0x10100000, 0x00110000, 0x10110000,
0x00100004, 0x10100004, 0x00110004, 0x10110004,
0x20100000, 0x30100000, 0x20110000, 0x30110000,
0x20100004, 0x30100004, 0x20110004, 0x30110004,
0x00001000, 0x10001000, 0x00011000, 0x10011000,
0x00001004, 0x10001004, 0x00011004, 0x10011004,
0x20001000, 0x30001000, 0x20011000, 0x30011000,
0x20001004, 0x30001004, 0x20011004, 0x30011004,
0x00101000, 0x10101000, 0x00111000, 0x10111000,
0x00101004, 0x10101004, 0x00111004, 0x10111004,
0x20101000, 0x30101000, 0x20111000, 0x30111000,
0x20101004, 0x30101004, 0x20111004, 0x30111004 ],
# for D bits (numbered as per FIPS 46) 8 9 11 12 13 14
[ 0x00000000, 0x08000000, 0x00000008, 0x08000008,
0x00000400, 0x08000400, 0x00000408, 0x08000408,
0x00020000, 0x08020000, 0x00020008, 0x08020008,
0x00020400, 0x08020400, 0x00020408, 0x08020408,
0x00000001, 0x08000001, 0x00000009, 0x08000009,
0x00000401, 0x08000401, 0x00000409, 0x08000409,
0x00020001, 0x08020001, 0x00020009, 0x08020009,
0x00020401, 0x08020401, 0x00020409, 0x08020409,
0x02000000, 0x0A000000, 0x02000008, 0x0A000008,
0x02000400, 0x0A000400, 0x02000408, 0x0A000408,
0x02020000, 0x0A020000, 0x02020008, 0x0A020008,
0x02020400, 0x0A020400, 0x02020408, 0x0A020408,
0x02000001, 0x0A000001, 0x02000009, 0x0A000009,
0x02000401, 0x0A000401, 0x02000409, 0x0A000409,
0x02020001, 0x0A020001, 0x02020009, 0x0A020009,
0x02020401, 0x0A020401, 0x02020409, 0x0A020409 ],
# for D bits (numbered as per FIPS 46) 16 17 18 19 20 21
[ 0x00000000, 0x00000100, 0x00080000, 0x00080100,
0x01000000, 0x01000100, 0x01080000, 0x01080100,
0x00000010, 0x00000110, 0x00080010, 0x00080110,
0x01000010, 0x01000110, 0x01080010, 0x01080110,
0x00200000, 0x00200100, 0x00280000, 0x00280100,
0x01200000, 0x01200100, 0x01280000, 0x01280100,
0x00200010, 0x00200110, 0x00280010, 0x00280110,
0x01200010, 0x01200110, 0x01280010, 0x01280110,
0x00000200, 0x00000300, 0x00080200, 0x00080300,
0x01000200, 0x01000300, 0x01080200, 0x01080300,
0x00000210, 0x00000310, 0x00080210, 0x00080310,
0x01000210, 0x01000310, 0x01080210, 0x01080310,
0x00200200, 0x00200300, 0x00280200, 0x00280300,
0x01200200, 0x01200300, 0x01280200, 0x01280300,
0x00200210, 0x00200310, 0x00280210, 0x00280310,
0x01200210, 0x01200310, 0x01280210, 0x01280310 ],
# for D bits (numbered as per FIPS 46) 22 23 24 25 27 28
[ 0x00000000, 0x04000000, 0x00040000, 0x04040000,
0x00000002, 0x04000002, 0x00040002, 0x04040002,
0x00002000, 0x04002000, 0x00042000, 0x04042000,
0x00002002, 0x04002002, 0x00042002, 0x04042002,
0x00000020, 0x04000020, 0x00040020, 0x04040020,
0x00000022, 0x04000022, 0x00040022, 0x04040022,
0x00002020, 0x04002020, 0x00042020, 0x04042020,
0x00002022, 0x04002022, 0x00042022, 0x04042022,
0x00000800, 0x04000800, 0x00040800, 0x04040800,
0x00000802, 0x04000802, 0x00040802, 0x04040802,
0x00002800, 0x04002800, 0x00042800, 0x04042800,
0x00002802, 0x04002802, 0x00042802, 0x04042802,
0x00000820, 0x04000820, 0x00040820, 0x04040820,
0x00000822, 0x04000822, 0x00040822, 0x04040822,
0x00002820, 0x04002820, 0x00042820, 0x04042820,
0x00002822, 0x04002822, 0x00042822, 0x04042822 ] )
_shifts2 = (0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0)
_con_salt = [
0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,
0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,
0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,
0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,
0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,
0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,
0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,
0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,
0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,
0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,
0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,
0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,
0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,
0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44 ]
_cov_2char = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
def _HPERM_OP(a):
"""Clever bit manipulation."""
t = ((a << 18) ^ a) & 0xcccc0000
return a ^ t ^ ((t >> 18) & 0x3fff)
def _PERM_OP(a,b,n,m):
"""Cleverer bit manipulation."""
t = ((a >> n) ^ b) & m
b = b ^ t
a = a ^ (t << n)
return a,b
def _set_key(password):
"""Generate DES key schedule from ASCII password."""
c,d = struct.unpack('<ii', password)
c = (c & 0x7f7f7f7f) << 1
d = (d & 0x7f7f7f7f) << 1
d,c = _PERM_OP(d,c,4,0x0f0f0f0f)
c = _HPERM_OP(c)
d = _HPERM_OP(d)
d,c = _PERM_OP(d,c,1,0x55555555)
c,d = _PERM_OP(c,d,8,0x00ff00ff)
d,c = _PERM_OP(d,c,1,0x55555555)
# Any sign-extended bits are masked off.
d = (((d & 0x000000ff) << 16) | (d & 0x0000ff00) |
((d & 0x00ff0000) >> 16) | ((c >> 4) & 0x0f000000))
c = c & 0x0fffffff
# Copy globals into local variables for loop.
shifts2 = _shifts2
skbc0, skbc1, skbc2, skbc3, skbd0, skbd1, skbd2, skbd3 = _skb
k = [0] * (_ITERATIONS * 2)
for i in range(_ITERATIONS):
# Only operates on top 28 bits.
if shifts2[i]:
c = (c >> 2) | (c << 26)
d = (d >> 2) | (d << 26)
else:
c = (c >> 1) | (c << 27)
d = (d >> 1) | (d << 27)
c = c & 0x0fffffff
d = d & 0x0fffffff
s = ( skbc0[ c & 0x3f ] |
skbc1[((c>> 6) & 0x03) | ((c>> 7) & 0x3c)] |
skbc2[((c>>13) & 0x0f) | ((c>>14) & 0x30)] |
skbc3[((c>>20) & 0x01) |
((c>>21) & 0x06) | ((c>>22) & 0x38)] )
t = ( skbd0[ d & 0x3f ] |
skbd1[((d>> 7) & 0x03) | ((d>> 8) & 0x3c)] |
skbd2[((d>>15) & 0x3f) ] |
skbd3[((d>>21) & 0x0f) | ((d>>22) & 0x30)] )
k[2*i] = ((t << 16) | (s & 0x0000ffff)) & 0xffffffff
s = (s >> 16) | (t & 0xffff0000)
# Top bit of s may be 1.
s = (s << 4) | ((s >> 28) & 0x0f)
k[2*i + 1] = s & 0xffffffff
return k
def _body(ks, E0, E1):
"""Use the key schedule ks and salt E0, E1 to create the password hash."""
# Copy global variable into locals for loop.
SP0, SP1, SP2, SP3, SP4, SP5, SP6, SP7 = _SPtrans
inner = range(0, _ITERATIONS*2, 2)
l = r = 0
for j in range(25):
l,r = r,l
for i in inner:
t = r ^ ((r >> 16) & 0xffff)
u = t & E0
t = t & E1
u = u ^ (u << 16) ^ r ^ ks[i]
t = t ^ (t << 16) ^ r ^ ks[i+1]
t = ((t >> 4) & 0x0fffffff) | (t << 28)
l,r = r,(SP1[(t ) & 0x3f] ^ SP3[(t>> 8) & 0x3f] ^
SP5[(t>>16) & 0x3f] ^ SP7[(t>>24) & 0x3f] ^
SP0[(u ) & 0x3f] ^ SP2[(u>> 8) & 0x3f] ^
SP4[(u>>16) & 0x3f] ^ SP6[(u>>24) & 0x3f] ^ l)
l = ((l >> 1) & 0x7fffffff) | ((l & 0x1) << 31)
r = ((r >> 1) & 0x7fffffff) | ((r & 0x1) << 31)
r,l = _PERM_OP(r, l, 1, 0x55555555)
l,r = _PERM_OP(l, r, 8, 0x00ff00ff)
r,l = _PERM_OP(r, l, 2, 0x33333333)
l,r = _PERM_OP(l, r, 16, 0x0000ffff)
r,l = _PERM_OP(r, l, 4, 0x0f0f0f0f)
return l,r
def crypt(password, salt):
"""Generate an encrypted hash from the passed password. If the password
is longer than eight characters, only the first eight will be used.
The first two characters of the salt are used to modify the encryption
algorithm used to generate in the hash in one of 4096 different ways.
The characters for the salt must be alphanumeric, '.' or '/'.
The returned hash begins with the two characters of the salt, and
should be passed as the salt to verify the password.
Example:
>>> from fcrypt import crypt
>>> password = 'AlOtBsOl'
>>> salt = 'cE'
>>> hash = crypt(password, salt)
>>> hash
'cEpWz5IUCShqM'
>>> crypt(password, hash) == hash
1
>>> crypt('IaLaIoK', hash) == hash
0
In practice, you would read the password using something like the
getpass module, and generate the salt randomly:
>>> import random, string
>>> saltchars = string.letters + string.digits + './'
>>> salt = random.choice(saltchars) + random.choice(saltchars)
"""
if len(salt) < 2:
salt = salt + 'AA'
Eswap0 = _con_salt[ord(salt[0])]
Eswap1 = _con_salt[ord(salt[1])] << 4
ks = _set_key((password + '\0\0\0\0\0\0\0\0')[:8])
out1,out2 = _body(ks, Eswap0, Eswap1)
# Convert numbers to big-endian...
be1, be2 = struct.unpack('>ii', struct.pack('<ii', out1, out2))
# then extract 24-bit subsets.
b24 = [(be1 >> 8) & 0xffffff,
((be1 << 16) & 0xff0000) | ((be2 >> 16) & 0xffff),
(be2 << 8) & 0xffff00]
# Convert to ASCII encoding, 4 characters for each 24 bits.
res = [salt[0], salt[1]]
for b in b24:
for i in range(18, -6, -6):
res.append(_cov_2char[(b >> i) & 0x3f])
return string.join(res[:13], '')
def _test():
"""Run doctest on fcrypt module."""
import doctest, fcrypt
return doctest.testmod(fcrypt)
if __name__ == '__main__':
_test()

View File

@ -1,22 +0,0 @@
#!/usr/bin/env python
# distutils setup script for fcrypt.
#
# Copyright (C) 2000, 2001 Carey Evans <careye@spamcop.net>
from distutils.core import setup
setup( name = 'fcrypt',
version = '1.2',
description = 'The Unix password crypt function.',
author = 'Carey Evans',
author_email = 'careye@spamcop.net',
url = 'http://home.clear.net.nz/pages/c.evans/sw/',
licence = 'BSD',
long_description = """\
A pure Python implementation of the Unix DES password crypt function,
based on Eric Young's fcrypt.c. It works with any version of Python
from version 1.5 or higher, and because it's pure Python it doesn't
need a C compiler to install it.""",
py_modules = ['fcrypt'] )

View File

@ -1,44 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: pass_crypt.py,v 1.3 2004/11/18 09:24:46 akm Exp $
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import CryptoPluginRegister
try:
from crypt import crypt
except:
from fcrypt.fcrypt import crypt
def cryptPassword(authSource, username, password):
u = authSource.listOneUser(username)
if not u:
salt = username[:2]
else:
salt=u[0]['password'][:2]
secret = crypt(password, salt)
return secret
CryptPlugin=CryptoPluginRegister('Crypt', 'crypt', 'Crypt', cryptPassword)
exUserFolder.cryptoSources['Crypt']=CryptPlugin

View File

@ -1,47 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: pass_md5.py,v 1.1 2004/11/10 14:15:52 akm Exp $
import md5, base64, string
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import CryptoPluginRegister
# Simple digest
def cryptPassword(authSource, username, password):
digest = md5.new()
digest.update(password)
digest = digest.digest()
secret = string.strip(base64.encodestring(digest))
return secret
# Digest includes username
# So two passwords for different users hash differently
def cryptPassword2(authSource, username, password):
newPass = username+':'+password
return cryptPassword(authSource, username, newPass)
MD5Plugin1=CryptoPluginRegister('MD51', 'MD5', 'MD5 Password Only', cryptPassword)
exUserFolder.cryptoSources['MD51']=MD5Plugin1
MD5Plugin2=CryptoPluginRegister('MD52', 'MD5', 'MD5 Username + Password', cryptPassword2)
exUserFolder.cryptoSources['MD52']=MD5Plugin2

View File

@ -1,31 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: pass_plain.py,v 1.1 2004/11/10 14:15:52 akm Exp $
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import CryptoPluginRegister
# Simple digest
def cryptPassword(authSource, username, password):
return password
PlainPlugin=CryptoPluginRegister('Plaintext', 'Plaintext', 'No Encryption', cryptPassword)
exUserFolder.cryptoSources['Plaintext']=PlainPlugin

View File

@ -1,41 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: pass_sha.py,v 1.1 2004/11/10 14:15:52 akm Exp $
import sha
from base64 import encodestring
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import CryptoPluginRegister
def cryptPassword(authSource, username, password):
return encodestring(sha.new(password).digest())
def cryptPassword2(authSource, username, password):
newPass = username+':'+password
return cryptPassword(authSource, username, newPass)
SHAPlugin1=CryptoPluginRegister('SHA1', 'SHA', 'SHA Password Only', cryptPassword)
exUserFolder.cryptoSources['SHA1']=SHAPlugin1
SHAPlugin2=CryptoPluginRegister('SHA2', 'SHA', 'SHA Username + Password', cryptPassword2)
exUserFolder.cryptoSources['SHA2']=SHAPlugin2

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,20 +0,0 @@
# This script interrogates the old-skool NuxUserGroups_support_branch
# group structure and outputs a tab-delimited file you can send to
# loadOldGroups. Just in case anyone is using it. :-)
#
# Matt Behrens <matt.behrens@kohler.com>
def getOldGroups(self):
"Reconstruct a group list from the old-style _groups property"
from string import join
props = self.currentPropSource.userProperties
groups = {}
for username in props.keys():
for groupname in props[username].getProperty('_groups', ()):
if not groups.has_key(groupname):
groups[groupname] = []
groups[groupname].append(username)
out = ''
for groupname in groups.keys():
out = out + '%s %s\n' % (groupname, join(groups[groupname], ' '))
return out

View File

@ -1,26 +0,0 @@
# This takes 'old_groups.txt' from var (create it using getOldGroups)
# and sets up all the groups therein using NuxUserGroups calls. This
# will load a group source if you need to do such a thing.
#
# Matt Behrens <matt.behrens@kohler.com>
def loadOldGroups(self):
from os.path import join as pathJoin
from string import split, strip
groups_file = open(pathJoin(CLIENT_HOME, 'old_groups.txt'), 'r')
out = ''
for group_line in groups_file.readlines():
group_line_elements = split(strip(group_line), ' ')
group_name = group_line_elements[0]
group_members = group_line_elements[1:]
if self.getGroupById(group_name, default=None) is None:
out = out + 'adding group %s\n' % group_name
self.userFolderAddGroup(group_name)
out = out + 'setting group %s membership to %s\n' % (group_name, group_members)
self.setUsersOfGroup(group_members, group_name)
return out

View File

@ -1,140 +0,0 @@
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: usAuthSourceMethods.py,v 1.3 2001/12/01 08:40:04 akm Exp $
#
########################################################################
#
# This is an example of an Extension Module to provide User Supplied
# Authentication Methods.
#
# It mimics the behaviour of the pgAuthSource Module, and the sql queries
# Used here would be added as ZSQLMethods in the usAuthSource Folder.
# (you can basically cut and paste them from the bottom of this .py file
# into the ZSQL Method Template Area
#
# It's not complete, but, you do get the idea...
#
# Each function becomes usFunctionName
#
# e.g. listOneUser -> usListOneUser
#
import string
from crypt import crypt
def listOneUser(self,username):
users = []
result=self.sqlListOneUser(username=username)
for n in result:
username=sqlattr(n,'username')
password=sqlattr(n,'password')
roles=string.split(sqlattr(n,'roles'))
N={'username':username, 'password':password, 'roles':roles}
users.append(N)
return users
def listUsers(self):
"""Returns a list of user names or [] if no users exist"""
users = []
result=self.sqlListUsers()
for n in result:
username=sqlattr(n,'username')
N={'username':username}
users.append(N)
return users
def getUsers(self):
"""Return a list of user objects or [] if no users exist"""
data=[]
try: items=self.listusers()
except: return data
for people in items:
roles=string.split(people['roles'],',')
user=User(people['username'], roles, '')
data.append(user)
return data
def cryptPassword(self, username, password):
salt =username[:2]
secret = crypt(password, salt)
return secret
def deleteUsers(self, userids):
for uid in userids:
self.sqlDeleteOneUser(userid=uid)
# Helper Functions...
from string import upper, lower
import Missing
mt=type(Missing.Value)
def typeconv(val):
if type(val)==mt:
return ''
return val
def sqlattr(ob, attr):
name=attr
if hasattr(ob, attr):
return typeconv(getattr(ob, attr))
attr=upper(attr)
if hasattr(ob, attr):
return typeconv(getattr(ob, attr))
attr=lower(attr)
if hasattr(ob, attr):
return typeconv(getattr(ob, attr))
raise NameError, name
########################################################################
# SQL METHODS USED ABOVE
# PASTE INTO ZSQL METHODS
# take note of what parameters are used in each query
########################################################################
_sqlListUsers="""
SELECT * FROM passwd
"""
_sqlListOneUser="""
SELECT * FROM passwd
where username=<dtml-sqlvar username type=string>
"""
_sqlDeleteOneUser="""
DELETE FROM passwd
where uid=<dtml-sqlvar userid type=int>
"""
_sqlInsertUser="""
INSERT INTO passwd (username, password, roles)
VALUES (<dtml-sqlvar username type=string>,
<dtml-sqlvar password type=string>,
<dtml-sqlvar roles type=string>)
"""
_sqlUpdateUserPassword="""
UPDATE passwd set password=<dtml-sqlvar password type=string>
WHERE username=<dtml-sqlvar username type=string>
"""
_sqlUpdateUser="""
UPDATE passwd set roles=<dtml-sqlvar roles type=string>
WHERE username=<dtml-sqlvar username type=string>
"""

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,32 +0,0 @@
#
# Extensible User Folder
#
# Null Group Source for exUserFolder
#
# Author: Brent Hendricks <bmh@users.sourceforge.net>
# $Id: GroupSource.py,v 1.1 2002/12/02 23:20:49 bmh Exp $
from Globals import DTMLFile
manage_addGroupSourceForm=DTMLFile('manage_addGroupSourceForm', globals(), __name__='manage_addGroupSourceForm')
def manage_addGroupSource(dispatcher, REQUEST):
""" Add a Group Source """
# Get the XUF object we're being added to
xuf = dispatcher.Destination()
groupId = REQUEST.get('groupId', None)
if groupId:
# Invoke the add method for this plugin
xuf.groupSources[groupId].manage_addMethod(xuf, REQUEST)
else:
raise "BadRequest", "Required parameter 'groupId' omitted"
dispatcher.manage_main(dispatcher, REQUEST)
class GroupSource:
pass

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2002/12/02 23:20:49 bmh Exp $
import GroupSource

View File

@ -1,33 +0,0 @@
<dtml-var manage_page_header>
<dtml-if currentGroupSource>
<dtml-var "MessageDialog(title='Group Source Exists', message='Error: There is already a group source here. Please delete it first', action='manage_main')">
<dtml-elif allDone>
<dtml-var expr="manage_addGroupSource(REQUEST)">
<dtml-elif groupId>
<dtml-call "REQUEST.set('groupForm',doGroupSourceForm(groupId=groupId))">
<dtml-var "groupForm(mapping=_)">
<dtml-else>
<dtml-var "DialogHeader(_.None,_,DialogTitle='Add eXtensible User Folder Group Source')">
<form action="&dtml-URL;" method="post">
<table cellspacing="2">
<tr>
<td align="left" valign="top">
<b><dtml-babel src="'en'">Group Source</dtml-babel></b>
</td>
<td>
<select name="groupId">
<dtml-in getGroupSources sort="name">
<option value="<dtml-var "_['sequence-item'].name">"><dtml-var description></option>
</dtml-in>
</select>
</td>
</tr>
<tr>
<td></td>
<td><br><input type="submit" value=" <dtml-babel src="'en'">Add</dtml-babel> "></td>
</tr>
</table>
</form>
<dtml-var DialogFooter>
</dtml-if>
<dtml-var manage_page_footer>

View File

@ -1,31 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: __init__.py,v 1.1 2004/11/10 14:15:53 akm Exp $
import nullGroupSource
# If this fails due to NUG being absent, just skip it
try:
import zodbGroupSource
except ImportError:
pass

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2004/11/10 14:15:53 akm Exp $
import nullGroupSource

View File

@ -1,21 +0,0 @@
<dtml-var "DialogHeader(_.None, _, DialogTitle='Add Basic Group Source', dialog_width='')">
<FORM ACTION="&dtml-URL;" METHOD="POST">
<dtml-in "REQUEST.form.keys()">
<dtml-if "getVariableType(REQUEST[_['sequence-item']]) == 'List'">
<dtml-let listVar=sequence-item>
<dtml-in "REQUEST[listVar]">
<input type="HIDDEN" name="<dtml-var listVar>:list" value="<dtml-var sequence-item>">
</dtml-in>
</dtml-let>
<dtml-else>
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-if>
</dtml-in>
<input type="HIDDEN" name="allDone" value="1">
<b><dtml-babel src="'en'">This Group Source has no configuration Items</dtml-babel></b><br>
<br>
<input type="SUBMIT" value="<dtml-babel src="'en'">Add</dtml-babel>">
</form>
<dtml-var DialogFooter>

View File

@ -1,34 +0,0 @@
#
# Extensible User Folder
#
# Null Group Source for exUserFolder
#
# Author: Brent Hendricks <bmh@users.sourceforge.net>
# $Id: nullGroupSource.py,v 1.1 2004/11/10 14:15:53 akm Exp $
from Globals import HTMLFile, INSTANCE_HOME
from OFS.Folder import Folder
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import PluginRegister
from Products.exUserFolder.nullPlugin import nullPlugin
def manage_addNullGroupSource(self, REQUEST):
""" Add a Group Source """
self.currentGroupSource=None
return ''
manage_addNullGroupSourceForm=HTMLFile('manage_addNullPluginSourceForm',globals())
manage_editNullGroupSourceForm=None
nullGroupReg=PluginRegister('nullGroupSource',
'Null Group Source',
nullPlugin,
manage_addNullGroupSourceForm,
manage_addNullGroupSource,
manage_editNullGroupSourceForm)
exUserFolder.groupSources['nullGroupSource']=nullGroupReg

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2004/11/10 14:15:54 akm Exp $
import zodbGroupSource

View File

@ -1,21 +0,0 @@
<dtml-var "DialogHeader(_.None,_,DialogTitle='Add ZODB Group Source')">
<FORM ACTION="&dtml-URL;" METHOD="POST">
<dtml-in "REQUEST.form.keys()">
<dtml-if "getVariableType(REQUEST[_['sequence-item']]) == 'List'">
<dtml-let listVar=sequence-item>
<dtml-in "REQUEST[listVar]">
<input type="HIDDEN" name="<dtml-var listVar>:list" value="<dtml-var sequence-item>">
</dtml-in>
</dtml-let>
<dtml-else>
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-if>
</dtml-in>
<input type="HIDDEN" name="allDone" value="1">
<b><dtml-babel src="'en'">This group source requires no user configuration items at this time.</dtml-babel></b><br>
<INPUT TYPE="SUBMIT" VALUE=" <dtml-babel src="'en'">NEXT</dtml-babel> ">
</FORM>
<dtml-var DialogFooter>

View File

@ -1,7 +0,0 @@
<dtml-var "DialogHeader(_.None,_,DialogTitle='ZODB Group Source',dialog_width='100%')">
<dtml-var manage_tabs>
<FORM ACTION="manage_main" METHOD="POST">
<b><dtml-babel src="'en'">This group source requires no user configuration items at this time.</dtml-babel></b><br>
<INPUT TYPE="SUBMIT" VALUE=" <dtml-babel src="'en'">OK</dtml-babel> ">
</FORM>
<dtml-var DialogFooter>

View File

@ -1,177 +0,0 @@
#
# Extensible User Folder
#
# ZODB Group Source for exUserFolder
#
# Author: Brent Hendricks <mh@users.sourceforge.net>
# $Id: zodbGroupSource.py,v 1.1 2004/11/10 14:15:54 akm Exp $
from Globals import HTMLFile, MessageDialog, INSTANCE_HOME,Acquisition, PersistentMapping
from OFS.Folder import Folder
from Products.ZSQLMethods.SQL import SQL
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import PluginRegister
from Products.NuxUserGroups.UserFolderWithGroups import Group, _marker
import time
import zLOG
import sys
manage_addGroupSourceForm=HTMLFile('manage_addzodbGroupSourceForm', globals())
def manage_addzodbGroupSource(self, REQUEST):
""" Add a ZODB Group Source """
o = zodbGroupSource()
self._setObject('zodbGroupSource', o, None, None, 0)
o = getattr(self, 'zodbGroupSource')
# Allow Prop Source to setup default users...
if hasattr(o, 'postInitialisation'):
o.postInitialisation(REQUEST)
self.currentGroupSource=o
manage_addzodbGroupSourceForm=HTMLFile('manage_addzodbGroupSourceForm', globals())
manage_editzodbGroupSourceForm=HTMLFile('manage_editzodbGroupSourceForm', globals())
#
# Very very simple thing, used as an example of how to write a property source
# Not recommended for large scale production sites...
#
class zodbGroupSource(Folder):
""" Store Group Data inside ZODB, the simplistic way """
meta_type='Group Source'
title='Simplistic ZODB Groups'
icon ='misc_/exUserFolder/exUserFolderPlugin.gif'
manage_editForm=manage_editzodbGroupSourceForm
manage_tabs=Acquisition.Acquired
def __init__(self):
self.id='zodbGroupSource'
self.groups=PersistentMapping()
def addGroup(self, groupname, title='', users=(), **kw):
"""Creates a group"""
if self.groups.has_key(groupname):
raise ValueError, 'Group "%s" already exists' % groupname
a = 'before: groupname %s groups %s' % (groupname, self.groups)
group = apply(Group, (groupname,), kw)
group.setTitle(title)
group._setUsers(users)
self.groups[groupname] = group
def getGroup(self, groupname, default=_marker):
"""Returns the given group"""
try:
group = self.groups[groupname]
except KeyError:
if default is _marker: raise
return default
return group
def delGroup(self, groupname):
"""Deletes the given group"""
usernames = self.groups[groupname].getUsers()
#self.delUsersFromGroup(usernames, groupname)
del self.groups[groupname]
def listGroups(self):
"""Returns a list of group names"""
return tuple(self.groups.keys())
def getGroupsOfUser(self, username):
"Get a user's groups"
groupnames = []
allnames = self.listGroups()
groupnames = filter(lambda g, u=username, self=self: u in self.groups[g].getUsers(), allnames)
return tuple(groupnames)
def setGroupsOfUser(self, groupnames, username):
"Set a user's groups"
oldGroups = self.getGroupsOfUser(username)
self.delGroupsFromUser(oldGroups, username)
self.addGroupsToUser(groupnames, username)
def addGroupsToUser(self, groupnames, username):
"Add groups to a user"
for name in groupnames:
group = self.groups[name]
if not username in group.getUsers():
group._addUsers([username])
def delGroupsFromUser(self, groupnames, username):
"Delete groups from a user"
for name in groupnames:
group = self.groups[name]
if username in group.getUsers():
group._delUsers([username])
def getUsersOfGroup(self, groupname):
"Get the users in a group"
return self.groups[groupname].getUsers()
def setUsersOfGroup(self, usernames, groupname):
"Set the users in a group"
# uniquify
dict = {}
for u in usernames: dict[u] = None
usernames = dict.keys()
self.groups[groupname]._setUsers(usernames)
def addUsersToGroup(self, usernames, groupname):
"Add users to a group"
# uniquify
dict = {}
for u in usernames: dict[u] = None
usernames = dict.keys()
self.groups[groupname]._addUsers(usernames)
def delUsersFromGroup(self, usernames, groupname):
"Delete users from a group"
# uniquify
dict = {}
for u in usernames: dict[u] = None
usernames = dict.keys()
self.groups[groupname]._delUsers(usernames)
def deleteUsers(self, usernames):
"Delete a list of users"
for user in usernames:
groups = self.getGroupsOfUser(user)
self.delGroupsFromUser(groups, user)
def postInitialisation(self, REQUEST):
pass
def manage_beforeDelete(self, item, container):
# Notify the exUserFolder that it doesn't have a group source anymore
container.currentGroupSource=None
zodbGroupReg=PluginRegister('zodbGroupSource','Simplistic ZODB Group Source',
zodbGroupSource, manage_addzodbGroupSourceForm,
manage_addzodbGroupSource,
manage_editzodbGroupSourceForm)
exUserFolder.groupSources['zodbGroupSource']=zodbGroupReg

View File

@ -1,91 +0,0 @@
XUF as a whole is covered by the BSD License, however it uses software
covered by other compatible licenses (see below)
------------------------------------------------------------------------
All of the documentation and software included in the exUserFolder
Releases is copyrighted by The Internet (Aust) Pty Ltd and contributors
ACN: 082 081 472 ABN: 83 082 081 472
Copyright 2001, 2002 The Internet (Aust) Pty Ltd
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
------------------------------------------------------------------------
This product includes software developed by Digital Creations for use in
the Z Object Publishing Environment (http://www.zope.org/)
Portions of smbAuthSource Copyright (C) 2001 Michael Teo
Portions of radiusAuthSource Copyright (C) 1999 Stuart Bishop
fcrypt is Copyright (C) 2001, 2001 Carey Evans
This product includes cryptographic software written by Eric Young
(eay@mincom.oz.au)
------------------------------------------------------------------------
Brief discussion of what the license means to you, not meant to be
all encompassing, but, to give you the general idea. This editorial does
not need to be distributed d8)
If you want to incorporate this product (or parts of it) into a commercial
product that's fine.
If you want to modify this product that's fine.
If you want to modify and distribute this product that's fine (even in
commercial products).
If you want to incorporate this into a larger work that's fine (even
if that work has a different license).
None of the previous items place any obligation of notification, compensation,
or return of code to us. In fact we don't care if you do these things. Go
forth and prosper. Basically as long as you recognise that this doesn't
belong to you, you can do what you want with it even charge money for it.
Note: If you do distribute this as source, then the XUF components are
removable and distributable independently of your license as a whole
(although that's a lot of trouble to go to when they could just download it
from the same place you did).
What you can't do, is claim it's yours, and this one thing encompasses a lot
of things, here's a few.
If it's not yours you can't;
Change the license even if you change the code since the copyright
of the modified files remains with the original copyright holders.
Use bits of it inside products that require the license to change, because
only the copyright holders have the right to modify the license (not a
concern for commercial projects, only some other Free/Open Source licenses).
Assign the copyright or other IP to any other party of the whole or any
part (even if you change the code), because it's not yours to give away or
sell to a 3rd party.
If the fact you can almost do whatever you want with this code isn't
liberal enough for you, contact us and we'll see what we can arrange.

View File

@ -1,27 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: LoginRequiredMessages.py,v 1.2 2001/12/01 08:40:03 akm Exp $
LoginRequiredMessages={
'session_expired':'Your Session has Expired',
'unauthorized':'Please Login',
'login_failed':'Login Failed',
}

View File

@ -1,25 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2005 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id:
import basicMemberSource
import nullMemberSource

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,22 +0,0 @@
<dtml-var "DialogHeader(DialogTitle='Change Password', dialog_width='')">
<form action="acl_users/manage_changePassword" method="POST">
<table>
<tr>
<td align="right"><b><dtml-babel src="'en'">Old Password</dtml-babel></b></td>
<td><input type="password" name="current_password"></td>
<tr>
<td align="right"><b><dtml-babel src="'en'">Password</dtml-babel></b></td>
<td><input type="password" name="password"></td>
</tr>
<td align="right"><b><dtml-babel src="'en'">Confirm Password</dtml-babel></b></td>
<td><input type="password" name="password_confirm"></td>
</tr>
<dtml-if "forgottenPasswords=='hint'">
<tr><td align="right"><b><dtml-babel src="'en'">Password Hint</dtml-babel></b></td>
<td><input type="text" name="user_hint" value="&dtml.missing-user_hint;"></td>
</tr>
</dtml-if>
</table>
<input type="submit" value=" <dtml-babel src="'en'">Change Password</dtml-babel> ">
</form>
<dtml-var DialogFooter>

View File

@ -1,31 +0,0 @@
<dtml-var "DialogHeader(DialogTitle='Signup', dialog_width='')">
<form action="acl_users/manage_signupUser" method="POST">
<table>
<tr>
<td align="right"><b><dtml-babel src="'en'">Username</dtml-babel></td>
<td><input name="username" type="text" value="&dtml.missing-username;"></td>
</tr>
<dtml-if "passwordPolicy=='user'">
<tr>
<td align="right"><b><dtml-babel src="'en'">Password</dtml-babel></b></td>
<td><input type="password" name="password" value="&dtml.missing-password;"></td>
</tr>
<td align="right"><b><dtml-babel src="'en'">Confirm Password</dtml-babel></b></td>
<td><input type="password" name="password_confirm"></td>
</tr>
<dtml-if "forgottenPasswords=='hint'">
<tr><td align="right"><b><dtml-babel src="'en'">Password Hint</dtml-babel></b></td>
<td><input type="text" name="user_hint" value="&dtml.missing-user_hint;"></td>
</tr>
</dtml-if>
</dtml-if>
<tr><td align="right"><b><dtml-babel src="'en'">Real Name</dtml-babel></b></td>
<td><input type="text" name="user_realname" value="&dtml.missing-user_realname;"></td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'"><dtml-babel src="'en'">Email</dtml-babel></dtml-babel></b></td>
<td><input type="text" name="user_email" value="&dtml.missing-user_email;"></td>
</tr>
</table>
<input type="submit" value=" <dtml-babel src="'en'">Signup</dtml-babel> ">
</form>
<dtml-var DialogFooter>

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2004/11/10 14:15:55 akm Exp $
import basicMemberSource

View File

@ -1,629 +0,0 @@
#
# Extensible User Folder
#
# Basic Membership Source for exUserFolder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: basicMemberSource.py,v 1.1 2004/11/10 14:15:55 akm Exp $
#
# Basically membership is a layer between the signup/login form, and
# the authentication layer, it uses the prop source of the users to
# store additional information about a user i.e. doesn't impact on the
# authentication source.
#
# Some membership features imply some extra properties for the user will
# be available; specifically at this time an email property.
#
# You also need a MailHost setup and ready to go for emailing stuff to users
#
import string,Acquisition
from random import choice
from Globals import HTMLFile, INSTANCE_HOME
from OFS.Folder import Folder
from OFS.DTMLMethod import DTMLMethod
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import PluginRegister
from base64 import encodestring
from urllib import quote
import zLOG
"""
Password Policy enforcement (min/max length, caps etc)
Create Password, or User Chooses.
Timing out of passwords...
Empty Password force change on login...
Create Home Directory
Copy files from Skelton Directory
EMail password hint to user (forgot my password)
Reset password and email user (needs plugin?)
Redirect on login to fixed or varying per username location.
Automatically add users, or manually approve of users.
"""
# Stupid little things for making a password
# Don't hassle me, it's supposed to be basic.
nouns=['ace', 'ant', 'arc', 'arm', 'axe',
'bar', 'bat', 'bee', 'bib', 'bin',
'can', 'cap', 'car', 'cat', 'cob',
'day', 'den', 'dog', 'dot', 'dux',
'ear', 'eel', 'egg', 'elf', 'elk',
'fad', 'fan', 'fat', 'fig', 'fez',
'gag', 'gas', 'gin', 'git', 'gum',
'hag', 'hat', 'hay', 'hex', 'hub']
pastConjs = [ 'did', 'has', 'was' ]
suffixes = [ 'ing', 'es', 'ed', 'ious', 'ily']
def manage_addBasicMemberSource(self, REQUEST):
""" Add a Membership Source """
pvfeatures=[]
minLength=0
passwordPolicy=''
createHomedir=0
homeRoot=''
copyFilesFrom=''
postLogin=''
postSignup=''
forgottenPasswords=''
defaultRoles=[]
usersCanChangePasswords=0
baseURL=''
loginPage=''
signupPage=''
passwordPage=''
mailHost=''
fixedDest=''
if REQUEST.has_key('basicmember_pvfeatures'):
pvfeatures=REQUEST['basicmember_pvfeatures']
if REQUEST.has_key('basicmember_roles'):
defaultRoles=REQUEST['basicmember_roles']
if not defaultRoles:
defaultRoles=['Member']
if 'minlength' in pvfeatures:
minLength=REQUEST['basicmember_minpasslen']
if REQUEST.has_key('basicmember_passwordpolicy'):
passwordPolicy=REQUEST['basicmember_passwordpolicy']
if REQUEST.has_key('basicmember_createhomedir'):
homeRoot=REQUEST['basicmember_homeroot']
createHomedir=1
if REQUEST.has_key('basicmember_copyfiles'):
copyFilesFrom=REQUEST['basicmember_copyfiles']
if REQUEST.has_key('basicmember_changepasswords'):
usersCanChangePasswords=1
if REQUEST.has_key('basicmember_fixeddest'):
fixedDest=''
forgottenPasswords=REQUEST['basicmember_forgottenpasswords']
postLogin=REQUEST['basicmember_postlogin']
baseURL=REQUEST['basicmember_baseurl']
loginPage=REQUEST['basicmember_loginpage']
signupPage=REQUEST['basicmember_signuppage']
passwordPage=REQUEST['basicmember_passwordpage']
siteEmail=REQUEST['basicmember_siteemail']
siteName=REQUEST['basicmember_sitename']
mailHost=REQUEST['basicmember_mailhost']
# postSignup=REQUEST['basicmember_postsignup']
#
# Yep this is obscene
#
o = BasicMemberSource(pvfeatures, minLength, passwordPolicy,
createHomedir, copyFilesFrom, postLogin,
homeRoot, forgottenPasswords, defaultRoles,
usersCanChangePasswords, baseURL, loginPage,
signupPage, passwordPage, mailHost,
siteName, siteEmail, fixedDest)
self._setObject('basicMemberSource', o, None, None, 0)
o = getattr(self, 'basicMemberSource')
if hasattr(o, 'postInitialisation'):
o.postInitialisation(REQUEST)
self.currentMembershipSource=o
return ''
manage_addBasicMemberSourceForm=HTMLFile('manage_addBasicMemberSourceForm',
globals())
manage_editBasicMemberSourceForm=HTMLFile('manage_editBasicMemberSourceForm',
globals())
#
# Crap, I don't know why I called this basic, I'd hate to see a
# complicated one.
#
class BasicMemberSource(Folder):
""" Provide High Level User Management """
meta_type="Membership Source"
title="Basic Membership Source"
icon ='misc_/exUserFolder/exUserFolderPlugin.gif'
manage_tabs=Acquisition.Acquired
manage_editForm=manage_editBasicMemberSourceForm
# Ugh...
def __init__(self, pvFeatures=[], minLength=0, passwordPolicy='',
createHomeDir=0, copyFilesFrom='', postLogin='', homeRoot='',
forgottenPasswords='', defaultRoles=[], usersCanChangePasswords=0,
baseURL='', loginPage='', signupPage='', passwordPage='',
mailHost='', siteName='', siteEmail='', fixedDest=''):
self.id='basicMemberSource'
self.pvFeatures=pvFeatures
self.minLength=int(minLength)
self.passwordPolicy=passwordPolicy
self.createHomeDir=createHomeDir
self.copyFilesFrom=copyFilesFrom
self.postLogin=postLogin
self.homeRoot=homeRoot
self.forgottenPasswords=forgottenPasswords
self.defaultRoles=defaultRoles
self.usersCanChangePasswords=usersCanChangePasswords
self.baseURL=baseURL
self.loginPage=loginPage
self.signupPage=signupPage
self.passwordPage=passwordPage
self.siteName=siteName
self.siteEmail=siteEmail
self.fixedDest=fixedDest
_SignupForm=HTMLFile('SignupForm', globals())
SignupForm=DTMLMethod()
SignupForm.manage_edit(data=_SignupForm, title='Signup Form')
self._setObject('SignupForm', SignupForm)
_PasswordForm=HTMLFile('PasswordForm', globals())
PasswordForm=DTMLMethod()
PasswordForm.manage_edit(data=_PasswordForm,
title='Change Password')
self._setObject('PasswordForm', PasswordForm)
self.mailHost=mailHost
_newPasswordEmail=HTMLFile('newPasswordEmail', globals())
newPasswordEmail=DTMLMethod()
newPasswordEmail.manage_edit(data=_newPasswordEmail,
title='Send New Password')
self._setObject('newPasswordEmail', newPasswordEmail)
_forgotPasswordEmail=HTMLFile('forgotPasswordEmail', globals())
forgotPasswordEmail=DTMLMethod()
forgotPasswordEmail.manage_edit(data=_forgotPasswordEmail,
title='Send Forgotten Password')
self._setObject('forgotPasswordEmail', forgotPasswordEmail)
_passwordHintEmail=HTMLFile('passwordHintEmail', globals())
passwordHintEmail=DTMLMethod()
passwordHintEmail.manage_edit(data=_passwordHintEmail,
title='Send Forgotten Password Hint')
self._setObject('passwordHintEmail', passwordHintEmail)
def postInitialisation(self, REQUEST):
if self.createHomeDir and self.homeRoot:
self.findHomeRootObject()
else:
self.homeRootObj=None
if self.copyFilesFrom:
self.findSkelRootObject()
else:
self.homeSkelObj=None
# The nice sendmail tag doesn't allow expressions for
# the mailhost
self.mailHostObject=getattr(self, self.mailHost)
def manage_editMembershipSource(self, REQUEST):
""" Edit a basic Membership Source """
if REQUEST.has_key('pvfeatures'):
self.pvFeatures=REQUEST['pvfeatures']
else:
self.pvFeatures=[]
if REQUEST.has_key('minpasslength'):
self.minLength=REQUEST['minpasslength']
if REQUEST.has_key('createhomedir'):
createHomeDir=1
else:
createHomeDir=0
if createHomeDir:
self.copyFilesFrom=REQUEST['copyfiles']
if self.copyFilesFrom:
self.findSkelRootObject()
else:
self.homeRoot=REQUEST['homeroot']
self.findHomeRootObject()
if REQUEST.has_key('memberroles'):
self.defaultRoles=REQUEST['memberroles']
if REQUEST.has_key('changepasswords'):
self.usersCanChangePasswords=1
else:
self.usersCanChangePasswords=0
self.postLogin=REQUEST['postlogin']
if REQUEST.has_key('fixeddest'):
self.fixedDest=REQUEST['fixeddest']
self.baseURL=REQUEST['baseurl']
self.loginPage=REQUEST['loginpage']
self.signupPage=REQUEST['signuppage']
self.passwordPage=REQUEST['passwordpage']
self.siteName=REQUEST['sitename']
self.siteEmail=REQUEST['siteemail']
return self.MessageDialog(self,
title ='Updated!',
message="Membership was Updated",
action ='manage_editMembershipSourceForm',
REQUEST=REQUEST)
def forgotPassword(self, REQUEST):
username=REQUEST['username']
curUser=self.getUser(username)
if not curUser:
return self.MessageDialog(self,
title ='No such user',
message="No users matching that username were found.",
action ='%s/%s'%(self.baseURL, self.loginPage),
REQUEST=REQUEST)
userEmail=curUser.getProperty('email')
userName=curUser.getProperty('realname')
if self.forgottenPasswords == "hint":
passwordHint=curUser.getProperty('passwordhint')
self.passwordHintEmail(self,
REQUEST=REQUEST,
username=username,
hint=passwordHint,
realname=userName,
email=userEmail)
else:
# make a new password, and mail it to the user
password = self.generatePassword()
curCrypt=self.currentAuthSource.cryptPassword(username,password)
# Update the user
bogusREQUEST={}
#bogusREQUEST['username']=username
bogusREQUEST['password']=password
bogusREQUEST['password_confirm']=password
bogusREQUEST['roles']=curUser.roles
self.manage_editUser(username, bogusREQUEST)
self.forgotPasswordEmail(self,
REQUEST=REQUEST,
username=username,
password=password,
realname=userName,
email=userEmail)
return self.MessageDialog(self,
title ='Sent!',
message="Password details have been emailed to you",
action ='%s/%s'%(self.baseURL, self.loginPage),
REQUEST=REQUEST)
def changeProperties(self, REQUEST):
curUser=self.listOneUser(REQUEST['AUTHENTICATED_USER'].getUserName())
curUser=curUser[0]
if not curUser:
return self.MessageDialog(self,
title ='Erm!',
message="You don't seem to be logged in",
action ='%s/%s'%(self.baseURL, self.passwordPage),
REQUEST=REQUEST)
self.currentPropSource.updateUser(curUser['username'],REQUEST)
return self.MessageDialog(self,
title ='Properties updated',
message="Your properties have been updated",
action =self.baseURL,
REQUEST=REQUEST,
)
def changePassword(self, REQUEST):
if not self.usersCanChangePasswords:
return ''
curUser=self.listOneUser(REQUEST['AUTHENTICATED_USER'].getUserName())
curUser=curUser[0]
if not curUser:
return self.MessageDialog(
title ='Erm!',
message="You don't seem to be logged in",
action ='%s/%s'%(self.baseURL, self.passwordPage),
REQUEST=REQUEST)
curCrypt=self.currentAuthSource.cryptPassword(curUser['username'],REQUEST['current_password'])
if curCrypt != curUser['password']:
return self.MessageDialog(self,
title ='Password Mismatch',
message="Password is incorrect",
action ='%s/%s'%(self.baseURL, self.passwordPage),
REQUEST=REQUEST)
if REQUEST['password'] != REQUEST['password_confirm']:
return self.MessageDialog(self,
title ='Password Mismatch',
message="Passwords do not match",
action ='%s/%s'%(self.baseURL, self.passwordPage),
REQUEST=REQUEST)
# OK the old password matches the one the user provided
# Both new passwords match...
# Time to validate against our normal set of rules...
#
if not self.validatePassword(REQUEST['password'], curUser['username']):
return self.MessageDialog(self,
title ='Password problem',
message="Your password is invalid, please choose another",
action ='%s/%s'%(self.baseURL, self.passwordPage),
REQUEST=REQUEST)
if self.passwordPolicy=='hint':
if not hasattr(REQUEST,'user_passwordhint'):
return self.MessageDialog(self,
title ='Password requires hint',
message='You must choose a password hint',
action ='%s/%s'%(self.baseURL, self.passwordPage),
REQUEST=REQUEST)
bogusREQUEST={}
bogusREQUEST['password']=REQUEST['password']
bogusREQUEST['password_confirm']=REQUEST['password']
bogusREQUEST['roles']=curUser['roles']
self.manage_editUser(curUser['username'],bogusREQUEST)
# update the cookie so he doesnt have to re-login:
if self.cookie_mode:
token='%s:%s' %(curUser['username'], REQUEST['password'])
token=encodestring(token)
token=quote(token)
REQUEST.response.setCookie('__ac', token, path='/')
REQUEST['__ac']=token
return self.MessageDialog(self,
title ='Password updated',
message="Your password has been updated",
action =self.baseURL,
REQUEST=REQUEST)
def goHome(self, REQUEST, RESPONSE):
redirectstring="%s/%s/%s/manage_main"%(self.baseURL, self.homeRoot, REQUEST.AUTHENTICATED_USER.getUserName())
RESPONSE.redirect(redirectstring)
return ''
# Tell exUserFolder where we want to go...
def getLoginDestination(self, REQUEST):
script=''
pathinfo=''
querystring=''
redirectstring=''
if self.postLogin=="destination":
script=REQUEST['SCRIPT_NAME']
pathinfo=REQUEST['PATH_INFO']
elif self.postLogin=="varied":
script=self.baseURL
pathinfo="/acl_users/goHome"
elif self.postLogin=="fixed":
pathinfo="%s"%(self.fixedDest)
if REQUEST.has_key('QUERY_STRING'):
querystring='?'+REQUEST['QUERY_STRING']
redirectstring=script+pathinfo
if querystring:
redirectstring=redirectstring+querystring
return redirectstring
def validatePassword(self, password, username):
if 'minlength' in self.pvFeatures:
if len(password) < self.minLength:
return 0
if 'mixedcase' in self.pvFeatures:
lower = 0
upper = 0
for c in password:
if c in string.lowercase:
lower = 1
if c in string.uppercase:
upper = 1
if not upper and lower:
return 0
if 'specialchar' in self.pvFeatures:
special = 0
for c in password:
if c in string.punctuation:
special = 1
break
elif c in string.digits:
special = 1
break
if not special:
return 0
#
# XXX Move this somewhere else
#
if 'notstupid' in self.pvFeatures:
email=''
# We try some permutations here...
curUser=self.getUser(username)
if curUser:
email = curUser.getProperty('email')
elif hasattr(self, 'REQUEST'):
if self.REQUEST.has_key('user_email'): # new signup
email=self.REQUEST['user_email']
elif self.REQUEST.has_key('email'):
email=self.REQUEST['email']
if ((string.find(password, username)>=0) or
( email and
(string.find(password,
string.split(email,'@')[0]) >=0))):
return 0
return 1
# These next two look the same (and they are for now), but, the reason I
# Don't use one single method, is I think that SkelObj might migrate to
# using full paths, not relative paths.
def findSkelRootObject(self):
# Parent should be acl_users
parent = getattr(self, 'aq_parent')
# This should be the root...
root = getattr(parent, 'aq_parent')
searchPaths = string.split(self.copyFilesFrom, '/')
for o in searchPaths:
if not getattr(root, o):
break
root = getattr(root, o)
self.homeSkelObj=root
def findHomeRootObject(self):
# Parent should be acl_users
parent = getattr(self, 'aq_parent')
# This should be the root...
root = getattr(parent, 'aq_parent')
searchPaths = string.split(self.homeRoot, '/')
for o in searchPaths:
if o not in root.objectIds():
root.manage_addFolder(id=o, title=o, createPublic=0, createUserF=0)
root = getattr(root, o)
self.homeRootObj=root
def makeHomeDir(self, username):
if not self.homeRootObj:
return
self.homeRootObj.manage_addFolder(id=username, title=username, createPublic=0, createUserF=0)
home = getattr(self.homeRootObj, username)
# Allow user to be in charge of their own destiny
# XXXX WARNING THIS IS A NORMAL FOLDER *SO USERS CAN ADD ANYTHING*
# YOU NEED TO CHANGE THE TYPE OF OBJECT ADDED FOR A USER UNLESS
# THIS IS WHAT YOU WANT TO HAPPEN
home.manage_addLocalRoles(userid=username, roles=['Manager'])
if self.copyFilesFrom and self.homeSkelObj and self.homeSkelObj.objectIds():
cp=self.homeSkelObj.manage_copyObjects(
self.homeSkelObj.objectIds())
home.manage_pasteObjects(cp)
# Fix it so the user owns their stuff
curUser=self.getUser(username).__of__(self.aq_parent)
home.changeOwnership(curUser, recursive=1)
def generatePassword(self):
password = (choice(nouns) + choice(pastConjs) +
choice(nouns) + choice(suffixes))
return password
def createUser(self, REQUEST):
if self.passwordPolicy == 'user':
if not self.validatePassword(REQUEST['password'], REQUEST['username']):
return self.MessageDialog(self,
title ='Password problem',
message='Your password is invalid, please choose another',
action ='%s/%s'%(self.baseURL, self.signupPage),
REQUEST=REQUEST)
if self.passwordPolicy=='hint':
if not hasattr(REQUEST,'user_passwordhint'):
return self.MessageDialog(self,
title ='Password requires hint',
message='You must choose a password hint',
action ='%s/%s'%(self.baseURL, self.signupPage),
REQUEST=REQUEST)
elif self.passwordPolicy == 'system':
REQUEST['password']=self.generatePassword()
REQUEST['password_confirm']=REQUEST['password']
# Email the password.
self.newPasswordEmail(self, REQUEST)
zLOG.LOG("exUserFolder.basicMemberSource", zLOG.BLATHER,
"Creating user",
"Passed all tests -- creating [%s]" % REQUEST['username'])
REQUEST['roles']=self.defaultRoles
self.manage_addUser(REQUEST) # Create the User...
if self.createHomeDir:
self.makeHomeDir(REQUEST['username'])
return self.MessageDialog(self,
title ='You have signed up',
message='You have been signed up succesfully',
action ='%s'%(self.baseURL),
REQUEST=REQUEST)
basicMemberReg=PluginRegister('basicMemberSource',
'Basic Membership Source',
BasicMemberSource,
manage_addBasicMemberSourceForm,
manage_addBasicMemberSource,
manage_editBasicMemberSourceForm)
exUserFolder.membershipSources['basicMemberSource']=basicMemberReg

View File

@ -1,15 +0,0 @@
<dtml-sendmail mailhost=mailHostObject>
To: <dtml-var realname> <<dtml-var email>>
From: <dtml-var siteName> <<dtml-var siteEmail>>
Subject: You forgot your password for <dtml-var siteName>
Dear <dtml-var realname>,
Your username is <dtml-var username> and your password is now
<dtml-var password>.
You should have tested this first, and now that you've tested it, you'll
see you need to customise this method.
</dtml-sendmail>

View File

@ -1,143 +0,0 @@
<dtml-var "DialogHeader(_.None, _, DialogTitle='Add Basic Membership Source', dialog_width='')">
<b><dtml-babel src="'en'">Membership requires a valid property source, you cannot use this with NULL Property Source</dtml-babel></b>
<FORM ACTION="&dtml-URL;" METHOD="POST">
<dtml-in "REQUEST.form.keys()">
<dtml-if "getVariableType(REQUEST[_['sequence-item']]) == 'List'">
<dtml-let listVar=sequence-item>
<dtml-in "REQUEST[listVar]">
<input type="HIDDEN" name="<dtml-var listVar>:list" value="<dtml-var sequence-item>">
</dtml-in>
</dtml-let>
<dtml-else>
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-if>
</dtml-in>
<input type="HIDDEN" name="doGroup" value="1">
<table cellspacing="2">
<tr><td align="right"><b><dtml-babel src="'en'">Site Name (used in emails)</dtml-babel></b></td>
<td><input type="text" name="basicmember_sitename">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Site Email (used for emails)</dtml-babel></b></td>
<td><input type="text" name="basicmember_siteemail">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Mail Host</dtml-babel></b></td>
<td>
<select name="basicmember_mailhost">
<dtml-in "MailHostIDs()">
<option value="<dtml-var sequence-item>">
<dtml-var sequence-key></option>
</dtml-in>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Site Base</dtml-babel></b></td>
<td><input type="text" name="basicmember_baseurl"
value="<dtml-var "absolute_url()">">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Relative Path (from base) of Login Page</dtml-babel></b></td>
<td><input type="text" name="basicmember_loginpage" value="LoginForm">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Relative Path (from base) of Signup Page</dtml-babel></b></td>
<td><input type="text" name="basicmember_signuppage" value="SignupForm">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Relative Path (from base) of Change Password Page</dtml-babel></b></td>
<td><input type="text" name="basicmember_passwordpage" value="ChangePasswordForm">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Password Validation Features</dtml-babel></b></td>
<td>
<select name="basicmember_pvfeatures:list" multiple>
<option value="minlength">Minimum Length</option>
<option value="mixedcase">Must have Mixed Case</option>
<option value="specichar">Must have Special Chars</option>
<option value="notstupid">Not Stupid (username/email/part of name)</option>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Minimum Length (0 if not required)</dtml-babel></b></td>
<td>
<input type="text" name="basicmember_minpasslen:int" value="0">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Password Policy</dtml-babel></b></td>
<td>
<select name="basicmember_passwordpolicy">
<option value="user">User Chooses</option>
<option value="system">System Chooses and emails User</option>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Forgotten Passwords</dtml-babel></b></td>
<td>
<select name="basicmember_forgottenpasswords">
<option value="hint"><dtml-babel src="'en'">Email a Hint</dtml-babel></option>
<option value="reset"><dtml-babel src="'en'">Reset and Email New password</dtml-babel></option>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Allow users to change passwords</dtml-babel></b></td>
<td>
<input type="checkbox" name="basicmember_changepasswords" checked><dtml-babel src="'en'">Yes</dtml-babel>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Create 'Home Directory'</dtml-babel></b></td>
<td>
<input type="checkbox" name="basicmember_createhomedir"><dtml-babel src="'en'">Yes</dtml-babel>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Relative Path to 'Home Directory' Root</dtml-babel></b></td>
<td>
<input type="text" name="basicmember_homeroot" value="Members">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Copy initial 'Home Directory' files from...(empty=No Copy)</dtml-babel></b></td>
<td>
<input type="text" name="basicmember_copyfiles", value="<dtml-var "_.string.join(getPhysicalPath()[1:], '/')">">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">After login....</dtml-babel></b></td>
<td>
<select name="basicmember_postlogin">
<option value="destination"><dtml-babel src="'en'">Go to intended destination</dtml-babel></option>
<option value="fixed"><dtml-babel src="'en'">Go to fixed destination</dtml-babel></option>
<option value="varied"><dtml-babel src="'en'">Go to Home Directory</dtml-babel></option>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Fixed Destination</dtml-babel></b></td>
<td>
<input type="text" name="basicmember_fixeddest">
</td>
</tr>
<tr>
<td valign="top" align="right"><b><dtml-babel src="'en'">Default Roles</dtml-babel></b></td>
<td align="left" valign="top">
<select name="basicmember_roles:list" size="5" multiple>
<dtml-in valid_roles>
<dtml-if expr="_vars['sequence-item'] != 'Anonymous'">
<dtml-if expr="_vars['sequence-item'] != 'Authenticated'">
<dtml-if expr="_vars['sequence-item'] != 'Shared'">
<option value="<dtml-var sequence-item html_quote>"><dtml-var sequence-item>
</dtml-if>
</dtml-if>
</dtml-if>
</dtml-in valid_roles>
</select>
</td>
</tr>
</table>
<input type="SUBMIT" value="<dtml-babel src="'en'">Add</dtml-babel>">
</form>
<dtml-var DialogFooter>

View File

@ -1,116 +0,0 @@
<dtml-var "DialogHeader(_.None, _, DialogTitle='Edit Basic Membership Source', dialog_width='')">
<dtml-var manage_tabs>
<FORM ACTION="manage_editMembershipSource" METHOD="POST">
<dtml-with currentMembershipSource>
<table cellspacing="2">
<tr><td align="right"><b><dtml-babel src="'en'">Site Name (used in emails)</dtml-babel></b></td>
<td><input type="text" name="sitename" value="&dtml.missing-siteName;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Site Email (used for emails)</dtml-babel></b></td>
<td><input type="text" name="siteemail" value="&dtml.missing-siteEmail;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Mail Host</dtml-babel></b></td>
<td>
<select name="mailhost">
<dtml-in "MailHostIDs()">
<option value="<dtml-var sequence-item>"<dtml-if "mailHost==_.getitem('sequence-item',0)"> selected</dtml-if>><dtml-var sequence-key></option>
</dtml-in>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Site Base</dtml-babel></b></td>
<td><input type="text" name="baseurl"
value="&dtml.missing-baseURL;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Relative Path (from base) of Login Page</dtml-babel></b></td>
<td><input type="text" name="loginpage" value="&dtml.missing-loginPage;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel>Relative Path (from base) of Signup Page</dtml-babel></b></td>
<td><input type="text" name="signuppage" value="&dtml.missing-signupPage;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Relative Path (from base) of Change Password Page</dtml-babel></b></td>
<td><input type="text" name="passwordpage" value="&dtml.missing-passwordPage;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Password Validation Features</dtml-babel></b></td>
<td>
<select name="pvfeatures:list" multiple>
<option value="minlength" <dtml-if "'minlength' in pvFeatures"> selected</dtml-if>><dtml-babel src="'en'">Minimum Length</dtml-babel></option>
<option value="mixedcase" <dtml-if "'mixedcase' in pvFeatures"> selected</dtml-if>><dtml-babel src="'en'">Must have Mixed Case</dtml-babel></option>
<option value="specichar" <dtml-if "'specichar' in pvFeatures"> selected</dtml-if>><dtml-babel src="'en'">Must have Special Chars</dtml-babel></option>
<option value="notstupid" <dtml-if "'notstupid' in pvFeatures"> selected</dtml-if>><dtml-babel src="'en'">Not Stupid (username/email/part of name)</dtml-babel></option>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Minimum Length (if required)</dtml-babel></b></td>
<td>
<input type="text" name="minpasslen:int" value="&dtml.missing-minLength;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Allow users to change passwords</dtml-babel></b></td>
<td>
<input type="checkbox" name="changepasswords"<dtml-if usersCanChangePasswords> checked</dtml-if>><dtml-babel src="'en'">Yes</dtml-babel>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Create 'Home Directory'</dtml-babel></b></td>
<td>
<input type="checkbox" name="createhomedir"<dtml-if createHomeDir> checked</dtml-if>><dtml-babel src="'en'">Yes</dtml-babel>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Path to 'Home Directory' Root</dtml-babel></b></td>
<td>
<input type="text" name="homeroot" value="&dtml.missing-homeRoot;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Copy initial 'Home Directory' files from...(empty=No Copy)</dtml-babel></b></td>
<td>
<input type="text" name="copyfiles" value="&dtml.missing-copyFilesFrom;">
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">After login....</dtml-babel></b></td>
<td>
<select name="postlogin">
<option value="destination"<dtml-if "postLogin=='destination'"> selected</dtml-if>><dtml-babel src="'en'">Go to intended destination</dtml-babel></option>
<option value="fixed"<dtml-if "postLogin=='fixed'"> selected</dtml-if>><dtml-babel src="'en'">Go to fixed destination</dtml-babel></option>
<option value="varied"<dtml-if "postLogin=='varied'"> selected</dtml-if>><dtml-babel src="'en'">Go to Home Directory</dtml-babel></option>
</select>
</td>
</tr>
<tr><td align="right"><b><dtml-babel src="'en'">Fixed Destination</dtml-babel></b></td>
<td>
<input type="text" name="fixeddest" value="&dtml.missing-fixedDest;">
</td>
</tr>
<tr>
<td valign="top" align="right"><b><dtml-babel src="'en'">Default Roles</dtml-babel></b></td>
<td align="left" valign="top">
<select name="memberroles:list" size="5" multiple>
<dtml-in valid_roles>
<dtml-if expr="_vars['sequence-item'] != 'Anonymous'">
<dtml-if expr="_vars['sequence-item'] != 'Authenticated'">
<dtml-if expr="_vars['sequence-item'] != 'Shared'">
<option value="<dtml-var sequence-item html_quote>"<dtml-if "_['sequence-item'] in defaultRoles"> selected</dtml-if>><dtml-var sequence-item>
</dtml-if>
</dtml-if>
</dtml-if>
</dtml-in valid_roles>
</select>
</td>
</tr>
</table>
<input type="SUBMIT" value=" <dtml-babel src="'en'">Update</dtml-babel> ">
</dtml-with>
</form>
<dtml-var DialogFooter>

View File

@ -1,16 +0,0 @@
<dtml-sendmail mailhost=mailHostObject>
To: <dtml-var user_realname> <<dtml-var user_email>>
From: <dtml-var siteName> <<dtml-var siteEmail>>
Subject: Welcome to <dtml-var siteName>
Dear <dtml-var user_realname>,
Welcome to <dtml-var siteName>.
Your username is <dtml-var username> and your password is <dtml-var password>.
You should have tested this first, and now that you've tested it, you'll
see you need to customise this method.
</dtml-sendmail>

View File

@ -1,15 +0,0 @@
<dtml-sendmail mailhost=mailHostObject>
To: <dtml-var realname> <<dtml-var email>>
From: <dtml-var siteName> <<dtml-var siteEmail>>
Subject: Hint for <dtml-var siteName>
Dear <dtml-var realname>,
Your username is <dtml-var username> and your password hint was;
<dtml-var hint>.
You should have tested this first, and now that you've tested it, you'll
see you need to customise this method.
</dtml-sendmail>

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2004/11/10 14:15:55 akm Exp $
import nullMemberSource

View File

@ -1,21 +0,0 @@
<dtml-var "DialogHeader(_.None, _, DialogTitle='Add Basic Membership Source', dialog_width='')">
<FORM ACTION="&dtml-URL;" METHOD="POST">
<dtml-in "REQUEST.form.keys()">
<dtml-if "getVariableType(REQUEST[_['sequence-item']]) == 'List'">
<dtml-let listVar=sequence-item>
<dtml-in "REQUEST[listVar]">
<input type="HIDDEN" name="<dtml-var listVar>:list" value="<dtml-var sequence-item>">
</dtml-in>
</dtml-let>
<dtml-else>
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-if>
</dtml-in>
<input type="HIDDEN" name="doGroup" value="1">
<b><dtml-babel src="'en'">This Membership Source has no configuration Items</dtml-babel></b><br>
<br>
<input type="SUBMIT" value="<dtml-babel src="'en'">Add</dtml-babel>">
</form>
<dtml-var DialogFooter>

View File

@ -1,49 +0,0 @@
#
# Extensible User Folder
#
# Null Membership Source for exUserFolder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: nullMemberSource.py,v 1.1 2004/11/10 14:15:55 akm Exp $
from Globals import HTMLFile, INSTANCE_HOME
from OFS.Folder import Folder
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import PluginRegister
from Products.exUserFolder.nullPlugin import nullPlugin
def manage_addNullMemberSource(self, REQUEST):
""" Add a Membership Source """
self.currentMembershipSource=None
return ''
manage_addNullMemberSourceForm=HTMLFile('manage_addNullPluginSourceForm',globals())
manage_editNullMemberSourceForm=None
nullMemberReg=PluginRegister('nullMemberSource',
'Null Membership Source',
nullPlugin,
manage_addNullMemberSourceForm,
manage_addNullMemberSource,
manage_editNullMemberSourceForm)
exUserFolder.membershipSources['nullMemberSource']=nullMemberReg

View File

@ -1,46 +0,0 @@
#
#
# (C) Copyright 2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: Plugins.py,v 1.5 2004/11/10 14:15:33 akm Exp $
import App, Globals, OFS
import string
import time
from Globals import ImageFile, HTMLFile, HTML, MessageDialog, package_home
from OFS.Folder import Folder
class PluginRegister:
def __init__(self, name, description, pluginClass,
pluginStartForm, pluginStartMethod,
pluginEditForm=None, pluginEditMethod=None):
self.name=name #No Spaces please...
self.description=description
self.plugin=pluginClass
self.manage_addForm=pluginStartForm
self.manage_addMethod=pluginStartMethod
self.manage_editForm=pluginEditForm
self.manage_editMethod=pluginEditMethod
class CryptoPluginRegister:
def __init__(self, name, crypto, description, pluginMethod):
self.name = name #No Spaces please...
self.cryptoMethod = crypto
self.description = description
self.plugin = pluginMethod

View File

@ -1,28 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2004 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: __init__.py,v 1.1 2004/11/10 14:15:55 akm Exp $
import nullPropSource
# aucune autre prop source pour ScoDoc

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,2 +0,0 @@
# $Id: __init__.py,v 1.1 2004/11/10 14:15:56 akm Exp $
import nullPropSource

View File

@ -1,21 +0,0 @@
<dtml-var "DialogHeader(_.None, _, DialogTitle='Add Basic Property Source', dialog_width='')">
<FORM ACTION="&dtml-URL;" METHOD="POST">
<dtml-in "REQUEST.form.keys()">
<dtml-if "getVariableType(REQUEST[_['sequence-item']]) == 'List'">
<dtml-let listVar=sequence-item>
<dtml-in "REQUEST[listVar]">
<input type="HIDDEN" name="<dtml-var listVar>:list" value="<dtml-var sequence-item>">
</dtml-in>
</dtml-let>
<dtml-else>
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-if>
</dtml-in>
<input type="HIDDEN" name="doMember" value="1">
<b><dtml-babel src="'en'">This Property Source has no configuration Items</dtml-babel></b><br>
<br>
<input type="SUBMIT" value="<dtml-babel src="'en'">Add</dtml-babel>">
</form>
<dtml-var DialogFooter>

View File

@ -1,50 +0,0 @@
#
# Extensible User Folder
#
# Null Membership Source for exUserFolder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: nullPropSource.py,v 1.1 2004/11/10 14:15:56 akm Exp $
from Globals import HTMLFile, INSTANCE_HOME
from OFS.Folder import Folder
from Products.exUserFolder.exUserFolder import exUserFolder
from Products.exUserFolder.Plugins import PluginRegister
from Products.exUserFolder.nullPlugin import nullPlugin
def manage_addNullPropSource(self, REQUEST):
""" Add a Property Source """
self.currentPropSource=None
return ''
manage_addNullPropSourceForm=HTMLFile('manage_addNullPluginSourceForm',globals())
manage_editNullPropSourceForm=None
nullPropReg=PluginRegister('nullPropSource',
'Null Property Source',
nullPlugin,
manage_addNullPropSourceForm,
manage_addNullPropSource,
manage_editNullPropSourceForm)
exUserFolder.propSources['nullPropSource']=nullPropReg

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,122 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: PropertyEditor.py,v 1.3 2002/01/29 17:42:02 alex_zxc Exp $
from Globals import DTMLFile, MessageDialog, INSTANCE_HOME
from string import join,strip,split,lower,upper,find
from urllib import quote, unquote
def editStringProperty( name, value):
""" """
return('<input type="TEXT" name="%s:string" value="%s">\n'%(name, value))
def viewStringProperty( name, value):
""" """
return('<input type="HIDDEN" name="propValue:string" value="%s"><br>%s<br>\n'%(value, value))
def editIntegerProperty( name, value):
""" """
return('<input type="TEXT" name="%s:int" value="%d">\n'%(name, value or 0))
def viewIntegerProperty( name, value):
""" """
return('<input type="HIDDEN" name="propValue:int" value="%d"><br>%d<br>\n'%(value or 0 , value or 0))
def editLongProperty( name, value):
""" """
return('<input type="TEXT" name="%s:int" value="%d">\n'%(name, value or 0))
def viewLongProperty( name, value):
""" """
return('<input type="HIDDEN" name="propValue:long" value="%d"><br>%d<br>\n'%(value or 0, value or 0))
def editFloatProperty( name, value):
""" """
return('<input type="TEXT" name="%s:float" value="%d">\n'%(name, value))
def viewFloatProperty( name, value):
""" """
return('<input type="HIDDEN" name="propValue:float" value="%f"><br>%f<br>\n'%(value, value))
def editListProperty( name, value):
a=''
if value:
a = a + 'Select Items to keep<br>\n'
a = a + '<select name="%s:list" multiple>\n'%(name)
for i in value:
a = a + (
'<option value="%s" SELECTED>%s\n'%(i, i))
a = a + '</select>\n<br>'
a = a + 'Add an item\n<br>'
a = a + '<input type="TEXT" name="%s:list">'%(name)
return(a)
def viewListProperty( name, value):
a=''
if value:
for i in value:
a = a + (
'<input type="HIDDEN" name="propValue:list" value="%s">\n'%(i))
a = a + '%s\n<br>'%(i)
return(a)
def editDictProperty( name, value):
""" """
a=''
if value and value.keys():
for i in value.keys():
a = a + '%s : <input type="TEXT" name="%s.%s" value="%s">\n<br>'%(i, name, i, value[i])
return a
def viewDictProperty( name, value):
""" """
a=''
if value and value.keys():
for i in value.keys():
a = a + '%s : <input type="HIDDEN" name="propValue.%s" value="%s">\n<br>'%(i, name, i, value[i])
a = a + '%s\n<br>'%(value[i])
return a
EditMethods={'String':editStringProperty,
'Integer':editIntegerProperty,
'Long':editLongProperty,
'Float':editFloatProperty,
'List':editListProperty,
'Dict':editDictProperty}
ViewMethods={'String':viewStringProperty,
'Integer':viewIntegerProperty,
'Long':viewLongProperty,
'Float':viewFloatProperty,
'List':viewListProperty,
'Dict':viewDictProperty}

View File

@ -1,22 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: __init__.py,v 1.2 2001/12/01 08:40:04 akm Exp $
import PropertyEditor

View File

@ -1,14 +0,0 @@
If you are upgrading an existing site from < 0.50
I have restructured the source tree. This will make this version
incompatible with previous versions, as the classes have moved. This
breaks upgrading existing installs unless you keep the old classes
around. If you only use external Auth/Prop/Group sources, you will
probably be unaffected.
This means for those of you using SQL or LDAP or any non-ZODB sources,
you can remove and then re-add your XUF acl_users to get going again.
If you are using a ZODB source, then you need to keep the old classes
and the old paths around (e.g. symlink zodbAuthSource to
AuthSources/zodbAuthSource).

View File

@ -1,243 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: User.py,v 1.10 2004/12/14 05:30:29 akm Exp $
##############################################################################
#
# Zope Public License (ZPL) Version 0.9.4
# ---------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions in source code must retain the above
# copyright notice, this list of conditions, and the following
# disclaimer.
#
# 6. Redistributions of any form whatsoever must retain the
# following acknowledgment:
#
# "This product includes software developed by Digital
# Creations for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND
# ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
# SHALL DIGITAL CREATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE.
#
##############################################################################
from AccessControl.User import BasicUser
from string import join,strip,split,lower,upper,find
class XUFUser(BasicUser):
icon='misc_/exUserFolder/exUser.gif'
# cacheable is a dict that must contain at least name, password,
# roles, and domains -- unless you're working with your own User class,
# in which case you need to override __init__ and define it yourself.
def __init__(self, cacheable, propSource, cryptPassword, authSource,
groupSource=None):
self.name =cacheable['name']
self.__ =cacheable['password']
if cacheable['roles']:
self.roles = filter(None, cacheable['roles'])
else:
self.roles = []
# domains may be passed as a string or a list
if type(cacheable['domains']) == type(''):
self.domains=filter(None, map(strip,
split(cacheable['domains'], ',')))
else:
self.domains=cacheable['domains']
self._authSource=authSource
self._propSource=propSource
self._groupSource=groupSource
self.cryptPassword=cryptPassword
def getUserName(self):
return self.name
def _getPassword(self):
return self.__
def getRoles(self):
return tuple(self.roles) + ('Authenticated',)
def getDomains(self):
return self.domains
# Ultra generic way of getting, checking and setting properties
def getProperty(self, property, default=None):
if self._propSource:
return self._propSource.getUserProperty(property, self.name, default)
def hasProperty(self, property):
if self._propSource:
return self._propSource.hasProperty(property)
def setProperty(self, property, value):
if property[0]=='_':
return
if self._propSource:
return self._propSource.setUserProperty(property, self.name, value)
def setTempProperty(self, property, value):
if property[0]=='_':
return
if self._propSource:
return self._propSource.setTempProperty(property, value)
def flushTempProperties(self):
if self._propSource:
return self._propSource.flushTempProperties()
def delProperty(self, property):
if property[0]=='_':
return
if self._propSource:
return self._propSource.delUserProperty(property, self.name)
def listProperties(self):
if self._propSource:
return self._propSource.listUserProperties(self.name)
# Try to allow User['property'] -- won't work for password d;)
def __getitem__(self, key):
# Don't return 'private' keys
if key[0] != '_':
if hasattr(self, key):
return getattr(self, key)
if self._propSource and self._propSource.hasProperty(key):
return self._propSource.getUserProperty(key, self.name)
raise KeyError, key
def __setitem__(self, key, value):
if key[0]=='_':
return
if self._propSource:
self._propSource.setUserProperty(key, self.name, value)
# List one user is supplied by the Auth Source...
def authenticate(self, listOneUser, password, request, remoteAuth=None):
result=listOneUser(username=self.name)
for people in result:
if remoteAuth:
return remoteAuth(self.name, password)
else:
secret=self.cryptPassword(self.name, password)
return secret==people['password']
return None
# You can set logout times or whatever here if you want to, the
# property source is still active.
def notifyCacheRemoval(self):
if self._propSource:
self._propSource.flushTempProperties()
# You must override this and __init__ if you are subclassing
# the user object, or your user object may not be reconstructed
# properly! All values in this dict must be non-Persistent objects
# or types, and may not hold any references to Persistent objects,
# or the cache will break.
def _getCacheableDict(self):
return {'name': self.name,
'password': self.__,
'roles': self.roles,
'domains': self.domains}
def getGroups(self):
if self._groupSource:
return self._groupSource.getGroupsOfUser(self.name)
else:
return ()
def _setGroups(self, groupnames):
if self._groupSource:
return self._groupSource.setGroupsOfUser(groupnames, self.name)
def _addGroups(self, groupnames):
if self._groupSource:
return self._groupSource.addGroupsToUser(groupnames, self.name)
def _delGroups(self, groupnames):
if self._groupSource:
return self._groupSource.delGroupsFromUser(groupnames, self.name)
def getId(self):
if self._propSource and self._propSource.getUserProperty('userid', self.name):
return self._propSource.getUserProperty('userid', self.name)
return self.name
#
# An Anonymous User for session tracking...
# Can set and get properties just like a normal user.
#
# These objects live in the cache, so, we have a __del__ method to
# clean ourselves up.
#
class XUFAnonUser(XUFUser):
def __init__(self, name, roles, propSource):
self.name =name
self.__ =''
self.roles =filter(None, roles)
self._propSource=propSource
def getRoles(self):
return tuple(self.roles) + ('Anonymous',)
def authenticate(self, listOneUser, password, request, remoteAuth=None):
return 1
def notifyCacheRemoval(self):
if self._propSource:
self._propSource.deleteUsers([self.name,])
# We now set up a dummy classes so that people can extend the User objects
# or override stuff with much less pain --akm
class User(XUFUser):
pass
class AnonUser(XUFAnonUser):
pass

View File

@ -1,4 +0,0 @@
*.pyc
*.pyo
*~
.*.swp

View File

@ -1,409 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: UserCache.py,v 1.16 2003/07/10 21:11:26 akm Exp $
# Module Level Caches for Various User Operations
from time import time
from BTrees.OOBTree import OOBTree
import threading
from Acquisition import aq_inner
from Products.exUserFolder.User import User
class UserCacheItem:
lastAccessed=0
def __init__(self, username, password, cacheable):
self.username=username
self.password=password
self.cacheable=cacheable
self.lastAccessed=time()
def touch(self):
self.lastAccessed=time()
def __repr__(self):
return self.username
class NegativeUserCacheItem(UserCacheItem):
def __init__(self, username):
self.username=username
self.lastAccessed=time()
class AdvancedCookieCacheItem(UserCacheItem):
lastAccessed=0
def __init__(self, username, password):
self.username=username
self.password=password
self.lastAccessed=time()
class SessionExpiredException(Exception):
'User Session Expired'
class UserCache:
def __init__(self, sessionLength):
self.sessionLength=sessionLength
self.cache=OOBTree()
self.hits=0
self.fail=0
self.nouser=0
self.attempts=0
self.timeouts=0
self.cacheStarted=time()
self.lock=threading.Lock()
def addToCache(self, username, password, User):
self.lock.acquire()
try:
if not self.sessionLength:
return
try:
u = self.cache.items(username)
if u:
for x in self.cache[username]:
self.cache.remove(x)
except:
pass
u = UserCacheItem(username, password, User._getCacheableDict())
self.cache[username]=u
finally:
self.lock.release()
def getUser(self, caller, username, password, checkpassword=1):
self.lock.acquire()
try:
if not self.sessionLength:
return None
self.attempts=self.attempts+1
u = None
try:
u = self.cache[username]
except KeyError:
self.nouser=self.nouser+1
return None
now = time()
if u:
if checkpassword and (u.password != password):
self.fail=self.fail+1
del self.cache[u.username]
elif self.sessionLength and (
(now - u.lastAccessed) > self.sessionLength):
del self.cache[u.username]
self.timeouts=self.timeouts+1
user_object=User(u.cacheable,
caller.currentPropSource,
caller.cryptPassword,
caller.currentAuthSource,
caller.currentGroupSource)
user_object.notifyCacheRemoval()
del u
raise SessionExpiredException
else:
u.touch()
self.hits=self.hits+1
return User(u.cacheable,
caller.currentPropSource,
caller.cryptPassword,
caller.currentAuthSource,
caller.currentGroupSource)
self.nouser=self.nouser+1
return None
finally:
self.lock.release()
def removeUser(self, username):
self.lock.acquire()
try:
if not self.sessionLength:
return
try:
if self.cache[username]:
del self.cache[username]
except:
pass
finally:
self.lock.release()
def getCacheStats(self):
self.lock.acquire()
try:
return (
{'attempts':self.attempts,
'hits':self.hits,
'fail':self.fail,
'misses':self.nouser,
'cachesize':len(self.cache),
'time':self.cacheStarted,
'timeouts':self.timeouts,
'length':self.sessionLength})
finally:
self.lock.release()
def getCurrentUsers(self, caller):
self.lock.acquire()
try:
x=[]
now = time()
for z in self.cache.keys():
u = self.cache[z]
if self.sessionLength and (
(now - u.lastAccessed) > self.sessionLength):
del self.cache[u.username]
self.timeouts=self.timeouts+1
user_object=User(u.cacheable,
caller.currentPropSource,
caller.cryptPassword,
caller.currentAuthSource,
caller.currentGroupSource)
user_object.notifyCacheRemoval()
del u
else:
x.append({'username':u.username,
'lastAccessed':u.lastAccessed})
return x
finally:
self.lock.release()
class NegativeUserCache:
def __init__(self, sessionLength):
self.sessionLength=sessionLength
self.cache=OOBTree()
self.hits=0
self.cacheStarted=time()
self.lock=threading.Lock()
def addToCache(self, username):
self.lock.acquire()
try:
if not self.sessionLength:
return
try:
u = self.cache.items(username)
if u:
for x in self.cache[username]:
self.cache.remove(x)
except:
pass
u = NegativeUserCacheItem(username)
self.cache[username]=u
finally:
self.lock.release()
def getUser(self, username):
self.lock.acquire()
try:
if not self.sessionLength:
return 0
u = None
try:
u = self.cache[username]
except KeyError:
return 0
now = time()
if u:
if self.sessionLength and (
(now - u.lastAccessed) > self.sessionLength):
del self.cache[u.username]
else:
# We don't touch negative user caches
# u.touch()
self.hits=self.hits+1
return 1
return 0
finally:
self.lock.release()
def removeUser(self, username):
self.lock.acquire()
try:
if not self.sessionLength:
return
try:
del self.cache[username]
except:
pass
finally:
self.lock.release()
class CookieCache:
def __init__(self, sessionLength):
self.sessionLength=sessionLength
self.cache=OOBTree()
self.hits=0
self.cacheStarted=time()
self.lock=threading.Lock()
def addToCache(self, username, password, key):
self.lock.acquire()
try:
if not self.sessionLength:
return
try:
u = self.cache.items(key)
if u:
for x in self.cache[key]:
self.cache.remove(x)
except:
pass
u = AdvancedCookieCacheItem(username, password)
self.cache[key]=u
finally:
self.lock.release()
def getUser(self, key):
self.lock.acquire()
try:
if not self.sessionLength:
return None
u = None
try:
u = self.cache[key]
except KeyError:
return None
now = time()
if u:
if self.sessionLength and (
(now - u.lastAccessed) > self.sessionLength):
del self.cache[key]
else:
# We don't touch negative user caches
# u.touch()
self.hits=self.hits+1
return u.username, u.password
return None
finally:
self.lock.release()
def removeUser(self, key):
self.lock.acquire()
try:
if not self.sessionLength:
return
try:
del self.cache[key]
except:
pass
finally:
self.lock.release()
class GlobalUserCache:
caches={}
def __init__(self):
self.lock = threading.Lock()
def createCache(self, who, sessionLength):
self.lock.acquire()
try:
self.caches[who]=UserCache(sessionLength)
return self.caches[who]
finally:
self.lock.release()
def getCache(self, who):
self.lock.acquire()
try:
if self.caches.has_key(who):
return self.caches[who]
else:
return None
finally:
self.lock.release()
def deleteCache(self, who):
self.lock.acquire()
try:
del self.caches[who]
finally:
self.lock.release()
class GlobalNegativeUserCache:
caches={}
def __init__(self):
self.lock = threading.Lock()
def createCache(self, who, sessionLength):
self.lock.acquire()
try:
self.caches[who]=NegativeUserCache(sessionLength)
return self.caches[who]
finally:
self.lock.release()
def getCache(self, who):
self.lock.acquire()
try:
if self.caches.has_key(who):
return self.caches[who]
else:
return None
finally:
self.lock.release()
def deleteCache(self, who):
self.lock.acquire()
try:
del self.caches[who]
finally:
self.lock.release()
class GlobalAdvancedCookieCache:
caches={}
def __init__(self):
self.lock = threading.Lock()
def createCache(self, who, sessionLength):
self.lock.acquire()
try:
self.caches[who]=CookieCache(sessionLength)
return self.caches[who]
finally:
self.lock.release()
def getCache(self, who):
self.lock.acquire()
try:
if self.caches.has_key(who):
return self.caches[who]
else:
return None
finally:
self.lock.release()
def deleteCache(self, who):
self.lock.acquire()
try:
del self.caches[who]
finally:
self.lock.release()

View File

@ -1,22 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000,2001 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: __init__.py,v 1.2 2001/12/01 08:40:04 akm Exp $
import UserCache

View File

@ -1,85 +0,0 @@
#
# Extensible User Folder
#
# (C) Copyright 2000-2005 The Internet (Aust) Pty Ltd
# ACN: 082 081 472 ABN: 83 082 081 472
# All Rights Reserved
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Author: Andrew Milton <akm@theinternet.com.au>
# $Id: __init__.py,v 1.18 2004/11/10 14:15:33 akm Exp $
import exUserFolder
import CryptoSources
import AuthSources
import PropSources
import MembershipSources
import GroupSources
from GroupSource import GroupSource
from App.ImageFile import ImageFile
import OFS
#
# Install a dummy ZBabel setup if we don't have ZBabel installed.
#
import dummyZBabelTag
# Methods we need access to from any ObjectManager context
legacy_methods = (
('manage_addexUserFolderForm', exUserFolder.manage_addexUserFolderForm),
('manage_addexUserFolder', exUserFolder.manage_addexUserFolder),
('getAuthSources', exUserFolder.getAuthSources),
#('getPropSources', exUserFolder.getPropSources),
('getCryptoSources', exUserFolder.getCryptoSources),
('getMembershipSources', exUserFolder.getMembershipSources),
('getGroupSources', exUserFolder.getGroupSources),
('doAuthSourceForm', exUserFolder.doAuthSourceForm),
#('doPropSourceForm', exUserFolder.doPropSourceForm),
('doMembershipSourceForm', exUserFolder.doMembershipSourceForm),
# ('doGroupSourceForm', exUserFolder.doGroupSourceForm),
('getVariableType', exUserFolder.getVariableType),
('DialogHeader', exUserFolder.exUserFolder.DialogHeader),
('DialogFooter', exUserFolder.exUserFolder.DialogFooter),
#('MailHostIDs', exUserFolder.MailHostIDs),
)
# Image files to place in the misc_ object so they are accesible from misc_/exUserFolder
misc_={'exUserFolder.gif': ImageFile('exUserFolder.gif', globals()),
'exUserFolderPlugin.gif': ImageFile('exUserFolderPlugin.gif', globals()),
'exUser.gif': ImageFile('exUser.gif', globals()),
}
def initialize(context):
"""
Register base classes
"""
context.registerClass(exUserFolder.exUserFolder,
meta_type="ex User Folder",
permission="Add exUser Folder",
constructors=(exUserFolder.manage_addexUserFolderForm,
exUserFolder.manage_addexUserFolder,),
legacy=legacy_methods,
icon="exUserFolder.gif")
context.registerClass(GroupSource.GroupSource,
meta_type="ex User Folder Group Source",
permission="Add exUser Folder",
constructors=(GroupSource.manage_addGroupSourceForm,
GroupSource.manage_addGroupSource,),
icon="exUserFolderPlugin.gif")

View File

@ -1,4 +0,0 @@
</td>
</tr>
</table>
</td></tr></table>

View File

@ -1,7 +0,0 @@
<table bgcolor="#808080" width="&dtml.missing-dialog_width;"><tr><td align="center" valign="middle">
<table width="100%" border="1" bgcolor="White" cellpadding="0" cellspacing="0">
<tr>
<td align="center"><table width="100%" bgcolor="#dddddd" border="0" cellspacing="0"><tr><td align="center"><font color="Black" size=+1 face="Helvetica"><b><dtml-babel src="'en'" literal="1"><dtml-var DialogTitle></dtml-babel></b></font></td></tr></table></td>
</tr>
<tr>
<td>

View File

@ -1,41 +0,0 @@
<head><body>
<FORM ACTION="<dtml-var action>" METHOD="POST" <dtml-if target>TARGET="<dtml-var target>"</dtml-if>>
<dtml-in "REQUEST.form.keys()">
<dtml-if "getVariableType(REQUEST[_['sequence-item']]) == 'List'">
<dtml-let listVar=sequence-item>
<dtml-in "REQUEST[listVar]">
<input type="HIDDEN" name="<dtml-var listVar>:list" value="<dtml-var sequence-item>">
</dtml-in>
</dtml-let>
<dtml-else>
<input type="HIDDEN" name="<dtml-var sequence-item>" value="<dtml-var "REQUEST[_.getitem('sequence-item',0)]">">
</dtml-if>
</dtml-in>
<dtml-var "DialogHeader(DialogTitle=title, dialog_width='')">
<TABLE BORDER="0" WIDTH="100%" CELLPADDING="10">
<TR>
<TD VALIGN="TOP">
<BR>
<CENTER><B><FONT SIZE="+6" COLOR="#77003B">!</FONT></B></CENTER>
</TD>
<TD VALIGN="TOP">
<BR><BR>
<CENTER>
<dtml-babel src="'en'" literal="1"><dtml-var message></dtml-babel>
</CENTER>
</TD>
</TR>
<TR>
<TD VALIGN="TOP">
</TD>
<TD VALIGN="TOP">
<CENTER>
<INPUT TYPE="SUBMIT" VALUE=" <dtml-babel src="'en'">Ok</dtml-babel> ">
</CENTER>
</TD>
</TR>
</TABLE>
<dtml-var DialogFooter>
</FORM>
</head></body>

View File

@ -1,176 +0,0 @@
<dtml-with "_(manage_options=filtered_manage_options())">
<dtml-if manage_options>
<dtml-call "REQUEST.set('n_', _.len(manage_options)-1)">
<dtml-call "REQUEST.set('a_', 0)">
<dtml-in manage_options mapping>
<dtml-if expr="URL[-(_.len(action)):]==action or
URL[-17:]=='/manage_workspace' and _['sequence-start']">
<dtml-call "REQUEST.set('a_', _['sequence-index'])">
</dtml-if>
<dtml-if "_.has_key('management_view') and management_view==label">
<dtml-call "REQUEST.set('a_', _['sequence-index'])">
</dtml-if>
</dtml-in>
<table cellpadding="0" cellspacing="0" width="100%" border="0">
<tr>
<td bgcolor="#000000" rowspan="5" width="10%" valign="bottom"
align="left">&nbsp;&nbsp;<img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" />
</td>
<td bgcolor="#000000" colspan="<dtml-var "4 * (n_ + 1)">"><img
src="&dtml-BASEPATH1;/p_/sp" width="1" height="5" alt="" /></td>
</tr>
<tr>
<dtml-in manage_options>
<dtml-if "_['sequence-index']==a_">
<td bgcolor="#ffffff" rowspan="2" valign="top"
align="left"><img src="&dtml-BASEPATH1;/p_/ltab" width="5"
height="5" alt="" /></td>
<td bgcolor="#ffffff"><img src="&dtml-BASEPATH1;/p_/sp"
width="1" height="2" alt="" /></td>
<td bgcolor="#ffffff" rowspan="2" valign="top"
align="right"><img src="&dtml-BASEPATH1;/p_/rtab" width="5"
height="5" alt="" /></td>
<td bgcolor="#000000" rowspan="4"><img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" /></td>
<dtml-else>
<td bgcolor="#efefef" rowspan="2" valign="top"
align="left"><img src="&dtml-BASEPATH1;/p_/ltab" width="5"
height="5" alt="" /></td>
<td bgcolor="#efefef"><img src="&dtml-BASEPATH1;/p_/sp"
width="1" height="2" alt="" /></td>
<td bgcolor="#efefef" rowspan="2" valign="top"
align="right"><img src="&dtml-BASEPATH1;/p_/rtab" width="5"
height="5" alt="" /></td>
<td bgcolor="#000000" rowspan="4"><img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" /></td>
</dtml-if>
</dtml-in>
</tr>
<tr>
<dtml-in manage_options mapping>
<dtml-if "_['sequence-index']==a_">
<td bgcolor="#ffffff" valign="bottom" class="tab-small"
align="center"><font face="Verdana, Arial, Helvetica"
size="1" color="#000000">&nbsp;<a <dtml-if
action>href="&dtml-action;"<dtml-else>href="&dtml-URL1;"</dtml-if
><dtml-if target> target="&dtml-target;"</dtml-if
>><span style="color: #000000;"><strong><dtml-babel src="'en'" literal="1">
<dtml-var label></dtml-babel></strong></span></a>&nbsp;</font></td>
<dtml-else>
<td bgcolor="#efefef" valign="bottom" class="tab-small"
align="center"><font face="Verdana, Arial, Helvetica"
size="1" color="#000000">&nbsp;<a <dtml-if
action>href="&dtml-action;"<dtml-else>href="&dtml-URL1;"</dtml-if
><dtml-if target> target="&dtml-target;"</dtml-if
>><span style="color: #000000;"><strong>
<dtml-babel src="'en'" literal="1"><dtml-var label></dtml-babel></strong></span></a>&nbsp;</font></td>
</dtml-if>
</dtml-in>
</tr>
<tr>
<dtml-in manage_options>
<dtml-if "_['sequence-index']==a_">
<td colspan="3" bgcolor="#ffffff"><img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" /></td>
<dtml-else>
<td colspan="3" bgcolor="#efefef"><img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" /></td>
</dtml-if>
</dtml-in>
</tr>
<tr>
<dtml-in manage_options>
<dtml-if "_['sequence-index']==a_">
<td colspan="3" bgcolor="#ffffff"><img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" /></td>
<dtml-else>
<td colspan="3" bgcolor="#c0c0c0"><img src="&dtml-BASEPATH1;/p_/sp"
width="2" height="1" alt="" /></td>
</dtml-if>
</dtml-in>
</tr>
</table>
</dtml-if>
<dtml-unless MANAGE_TABS_NO_BANNER>
<br />
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr class="location-bar">
<td align="left" valign="top">
<div class="std-text">
<dtml-if icon>
<img src="&dtml-BASEPATH1;/&dtml-icon;"
alt="&dtml-meta_type;" border="0" />
</dtml-if>
<strong>
<dtml-if meta_type>
<dtml-if class_manage_path>
<a href="&dtml-BASEPATH1;&dtml-class_manage_path;"
title="Manage the ZClass of this object">&dtml-meta_type;</a>
<dtml-else>
&dtml-meta_type;
</dtml-if>
<dtml-else>
Object
</dtml-if>
at <dtml-var expr="tabs_path_default(REQUEST)">
</strong>
<dtml-if locked_in_version>
<dtml-if modified_in_version>
<img src="&dtml-BASEPATH1;/p_/locked"
alt="This item has been modified in this version" />
<dtml-else>
<img src="&dtml-BASEPATH1;/p_/lockedo"
alt="This item has been modified in another version" />
(<em><dtml-var locked_in_version html_quote></em>)
</dtml-if>
</dtml-if>
<dtml-if wl_isLocked>
<img src="&dtml-BASEPATH1;/p_/davlocked"
alt="This item has been locked by WebDAV"
title="This item has been locked by WebDAV" />
</dtml-if wl_isLocked>
</div>
</td>
<dtml-if "_.has_key('help_topic') and _.has_key('help_product')">
<td align="right" valign="top">
<div class="std-text">
<dtml-var "HelpSys.helpLink(help_product, help_topic)">
</div>
</td>
<dtml-else>
<dtml-if manage_options>
<dtml-with "_(option=manage_options[a_])">
<dtml-if "option.has_key('help')">
<td align="right" valign="top">
<div class="std-text">
<dtml-var "HelpSys.helpLink(option['help'][0], option['help'][1])">
</div>
</td>
</dtml-if>
</dtml-with>
</dtml-if>
</dtml-if>
</tr>
</table>
<dtml-if Zope-Version>
<div class="system-msg">
<em>You are currently working in version <a href="&dtml-SERVER_URL;&dtml-Zope-Version;/manage_main"><dtml-var Zope-Version html_quote></a></em>
</div>
</dtml-if>
</dtml-unless>
<dtml-if manage_tabs_message>
<div class="system-msg">
<dtml-var manage_tabs_message>
(<dtml-var ZopeTime fmt="%Y-%m-%d %H:%M">)
</div>
</dtml-if>
</dtml-with>

View File

@ -1,19 +0,0 @@
<dtml-with "_(manage_options=filtered_manage_options())">
<dtml-if manage_options>
<table cellpadding="0" cellspacing="0" width="100%" border="2">
<tr><td>
<table cellpadding="0" cellspacing="5" width="100%" border="0">
<tr>
<td valign="bottom" align="left" class="tab-small">
<dtml-in manage_options mapping>
<b><a <dtml-if action>href="<dtml-var action>"
<dtml-else>href="<dtml-var URL1>" </dtml-if>
<dtml-if target> target="<dtml-var target>"</dtml-if>>
[<dtml-babel src="'en'" literal="1"><dtml-var label></dtml-babel>]</a></b>&nbsp;
</dtml-in>
</td>
</tr>
</table>
</td></tr></table>
</dtml-if>
</dtml-with>

View File

@ -1,119 +0,0 @@
Frequently Asked Questions
1. Why shouldn't I use Core Session Tracking + Login Manager?
XUF serves a different set of users to the combination above. XUF
aims to be a simple out of the box solution. Login Manager allows
for very complex authorisation schemes that can query multiple user
sources. We don't do that.
2. Why use XUF at all?
In its simplest configuration, XUF provides the same functionality
as the standard User Folder, but, is more secure. Passwords are
stored encrypted, which is not the case for the standard User Folder.
So even if you don't want to set properties on users, or any
membership facilities, there is a benefit to running XUF.
3. Do I have to have all this other stuff?
No. The only thing you need to enable is authentication. There is
a null property source, and a null membership source. Everything
other than authentication is optional.
4. Can I use it as a root folder?
Some people have reported success in doing so. We don't recommend
it for various reasons. The main one is that the internal Zope API
can change without warning, which could break XUF and lock you out
of your Zope. This can happen with any User Folder product. We
recommend you look at VHM and other Site Access methods to allow
you to store your main site in a sub-folder.
5. When will XUF support authentication against XYZ system?
That depends. First the active developers need to have an interest
in it, and more importantly they need to be able to test it. Writing
your authentication method is very simple, so if you understand
what you want to authenticate against, and know some python you
could write one in an hour. You can also use the usAuthSource to
write one using PythonScripts, ExternalMethods, DTML, or any other
callable method that Zope supports.
6. I wrote this cool authentication source can I get it into the main
distribution?
Yes and No. If your authentication is Open Source, and has a
compatible license with XUF, and doesn't require any external
libraries, odds are it'll go into the main distribution. If it
depends on external libraries, it's possible it can conditionally
go into the main distribution. The nice thing about XUF is that
Authentication, Property, and Membership sources are all packagable
as independent products, so you can distribute it as a standalone
product, and it'll work (without having to have the code drop into
the XUF directory either).
7. Is XUF going to be part of the Core Zope?
No idea. At the moment (0.10.5) XUF is probably not at a level that
Zope Corporation would consider mature enough for core inclusion
anyway.
Actually the answer now, is probably not. At a minimum smbAuthSource,
and radiusAuthSource would have to be stripped and distributed
seperately. Over and above that, I would have to assign Zope Corp
co-ownership rights on the IP, which amongst other things gives
them or anyone that buys them unlimited access to future derived
works. I refuse to do this on principle, the liberal licensing of
the product should be more than adequate for any (especially open
source) endeavour.
8. What's with the Management Screens?
It's a joke on the Zope World.
9. But they're really ugly I want to change them.
That's fine, you do that, that's the point.
10. Can I send you patches to put them back to standard Management
Screens?
You can put patches into the tracker at Source Forge if you want to.
11. HELP!!!! I tried to install XUF as my root folder, without
reading the FAQ, or really knowing what I'm doing, and now I'm
hosed!!!
That's a shame.
12. Will XUF work with ZEO?
Unknown. However, it's almost certain that in its current form
credential caching will not work across ZEO -- you will get a
seperate User Cache for each Zope Client (which isn't really all
that bad). However, it means that if you want to use Session Tracking,
you need to lock users to one particular server. Most commercial
Load Balancers do this for you anyhow. A persistent cache will form
part of an upcoming release which will allow all of this to work
transparently across ZEO farms.
13. Shouldn't it be EUF?
No, it should be XUF :-P
14. How can I log in a user via a form submission?
Yes, the key is sending the __ac_name and __ac_password (yes that's
two underscores in front) as form variables to any object covered
by the XUF.
This form will take your users to the /index_html and log them in.
You can place this anywhere in your site including /index_html.
<form action="/index_html">
Name: <input type="text" size="20" name="__ac_name"><br>
Password: <input type="password" size="20" name="__ac_password">
<input type="submit" value="Log in">
</form>
15. That Dialog box sure is ugly! How can I customize it so it looks
right in my site?
Under the contents tab add an object called MessageDialog , it can
be a dtml document, method, or even a page template. Make it look
how you want, it will acquire all objects from the folder the XUF
is in so you can use the standard_html_header, call scripts, etc.
16. Why can't I change the default crypto method?
Because someone will change it, and all the existing passwords will cease
to work. Then I'll get lots of hate-mail, or get slagged off on other mailing
lists :-)
17. Where is the Zen Master's Guide to exUserFolder?
Everywhere and nowhere.

Some files were not shown because too many files have changed in this diff Show More