[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IFilesystemAccess.py:1.2 IPosixFileSystem.py:1.2 IReadFileSystem.py:1.2 IUsernamePassword.py:1.2 IWriteFileSystem.py:1.2 OSFileSystem.py:1.2 PublisherFileSystem.py:1.2 TestFilesystemAccess.py:1.2 UsernamePassword.py:1.2 __init__.py:1.2
Jim Fulton
jim@zope.com
Mon, 10 Jun 2002 19:30:08 -0400
Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS
In directory cvs.zope.org:/tmp/cvs-serv20468/lib/python/Zope/Server/VFS
Added Files:
IFilesystemAccess.py IPosixFileSystem.py IReadFileSystem.py
IUsernamePassword.py IWriteFileSystem.py OSFileSystem.py
PublisherFileSystem.py TestFilesystemAccess.py
UsernamePassword.py __init__.py
Log Message:
Merged Zope-3x-branch into newly forked Zope3 CVS Tree.
=== Zope3/lib/python/Zope/Server/VFS/IFilesystemAccess.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from Interface import Interface
+
+# XXX This interface should be in a more central location.
+
+class IFilesystemAccess(Interface):
+ """Provides authenticated access to a filesystem.
+ """
+
+ def authenticate(credentials):
+ """Verifies filesystem access based on the presented credentials.
+
+ Should raise Unauthorized if the user can not be authenticated.
+
+ This method only checks general access and is not used for each
+ call to open(). Rather, open() should do its own verification.
+ """
+
+ def open(credentials):
+ """Returns an IReadFilesystem or IWriteFilesystem.
+
+ Should raise Unauthorized if the user can not be authenticated.
+ """
=== Zope3/lib/python/Zope/Server/VFS/IPosixFileSystem.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from IWriteFileSystem import IWriteFileSystem
+from IReadFileSystem import IReadFileSystem
+
+
+class IPosixFileSystem(IWriteFileSystem, IReadFileSystem):
+ """
+ """
+
+ def chmod(path, mode):
+ """Change the access permissions of a file.
+ """
+
+ def chown(path, uid, gid):
+ """Change the owner and group id of path to numeric uid and gid.
+ """
+
+ def link(src, dst):
+ """Create a heard link to a file.
+ """
+
+ def mkfifo(path, mode=777):
+ """Create a FIFO (a POSIX named pipe).
+ """
+
+ def symlink(src, dst):
+ """Create a symbolic link at dst pointing to src.
+ """
+
=== Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from Interface import Interface
+
+class IReadFileSystem(Interface):
+ """We want to provide a complete wrapper around any and all read
+ filesystem operations.
+
+ Opening files for reading, and listing directories, should
+ return a producer.
+
+ All paths are POSIX paths, even when run on Windows,
+ which mainly means that FS implementations always expect forward
+ slashes, and filenames are case-sensitive.
+
+ Note: A file system should *not* store any state!
+ """
+
+ def exists(path):
+ """Test whether a path exists.
+ """
+
+ def isdir(path):
+ """Test whether a path is a directory.
+ """
+
+ def isfile(path):
+ """Test whether a path is a file.
+ """
+
+ def listdir(path, with_stats=0, pattern='*'):
+ """Return a listing of the directory at 'path' The empty
+ string indicates the current directory. If 'with_stats' is set,
+ instead return a list of (name, stat_info) tuples. All file
+ names are filtered by the globbing pattern. (See the 'glob'
+ module in the Python standard library.)
+ """
+ return list(tuple(str, str))
+
+ def readfile(path, mode, outstream, start=0, end=-1):
+ """Outputs the file at path to a stream.
+ """
+
+ def stat(path):
+ """Return the equivalent of os.stat() on the given path:
+
+ (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)
+ """
=== Zope3/lib/python/Zope/Server/VFS/IUsernamePassword.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from Interface import Interface
+
+# XXX These interfaces should be located in a more central location.
+# (so I don't mind putting them together in one module for now ;-) )
+
+
+class ICredentials(Interface):
+ """Base interface for presentation of authentication credentials.
+
+ Different kinds of credentials include username/password, client
+ certificate, IP address and port, etc., including combinations.
+ """
+
+
+class IUsernamePassword(ICredentials):
+ """A type of authentication credentials consisting of user name and
+ password. The most recognized form of credentials.
+ """
+
+ def getUserName():
+ """Returns the user name presented for authentication.
+ """
+
+ def getPassword():
+ """Returns the password presented for authentication.
+ """
+
=== Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from Interface import Interface
+
+class IWriteFileSystem(Interface):
+ """We want to provide a complete wrapper around any and all write
+ filesystem operations.
+
+ Notes:
+ - A file system should *not* store any state!
+ - Most of the commands copy the functionality given in os.
+ """
+
+ def mkdir(path, mode=777):
+ """Create a directory.
+ """
+
+ def remove(path):
+ """Remove a file. Same as unlink.
+ """
+
+ def rmdir(path):
+ """Remove a directory.
+ """
+
+ def rename(old, new):
+ """Rename a file or directory.
+ """
+
+ def writefile(path, mode, instream, start=0):
+ """Write data to a file.
+ """
+
+ def check_writable(path):
+ """Ensures a path is writable. Throws an IOError if not."""
+
=== Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+import os
+import re
+import stat
+import time
+import fnmatch
+
+from IPosixFileSystem import IPosixFileSystem
+
+
+class OSFileSystem(object):
+ """Generic OS FileSystem implementation.
+
+ The root of this file system is a string describing the path
+ to the directory used as root.
+ """
+
+ __implements__ = IPosixFileSystem
+
+ copy_bytes = 65536
+
+
+ def __init__ (self, root):
+ self.root = root
+
+ ############################################################
+ # Implementation methods for interface
+ # Zope.Server.VFS.IPosixFileSystem.IPosixFileSystem
+
+ def chmod(self, path, mode):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate (path)
+ return os.chmod(p, mode)
+
+
+ def chown(self, path, uid, gid):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate (path)
+ return os.chown(p, uid, gid)
+
+
+ def link(self, src, dst):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ src = self.translate(src)
+ dst = self.translate(dst)
+ return os.link(src, dst)
+
+
+ def mkfifo(self, path, mode=6*2**6):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ return os.mkfifo(path, mode)
+
+
+ def symlink(self, src, dst):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ src = self.translate(src)
+ dst = self.translate(dst)
+ return os.symlink(src, dst)
+
+
+ ######################################
+ # from: Zope.Server.VFS.IReadFileSystem.IReadFileSystem
+
+ def exists(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ p = self.translate(path)
+ return os.path.exists(p)
+
+
+ def isdir(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ p = self.translate(path)
+ return os.path.isdir(p)
+
+
+ def isfile(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ p = self.translate(path)
+ return os.path.isfile(p)
+
+
+ def listdir(self, path, with_stats=0, pattern='*'):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ p = self.translate(path)
+ # list the directory's files
+ ld = os.listdir(p)
+ # filter them using the pattern
+ ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld)
+ # sort them alphabetically
+ ld.sort()
+ if not with_stats:
+ result = ld
+ else:
+ result = []
+ for file in ld:
+ path = os.path.join(p, file)
+ stat = safe_stat(path)
+ if stat is not None:
+ result.append((file, stat))
+ return result
+
+
+ def readfile(self, path, mode, outstream, start=0, end=-1):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ p = self.translate(path)
+ instream = open(p, mode)
+ if start:
+ instream.seek(start)
+ pos = start
+ while end < 0 or pos < end:
+ toread = self.copy_bytes
+ if end >= 0:
+ toread = min(toread, end - pos)
+ data = instream.read(toread)
+ if not data:
+ break
+ pos += len(data)
+ outstream.write(data)
+
+
+ def stat(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ p = self.translate(path)
+ return os.stat(p)
+
+
+ ######################################
+ # from: Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem
+
+ def mkdir(self, path, mode=6*2**6):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate(path)
+ return os.mkdir(p, mode)
+
+
+ def remove(self, path):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate (path)
+ return os.remove(p)
+
+
+ def rmdir(self, path):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate (path)
+ return os.rmdir(p)
+
+
+ def rename(self, old, new):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ old = self.translate(old)
+ new = self.translate(new)
+ return os.rename(old, new)
+
+
+ def writefile(self, path, mode, instream, start=0):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate(path)
+ outstream = open(p, mode)
+ if start:
+ outstream.seek(start)
+ while 1:
+ data = instream.read(self.copy_bytes)
+ if not data:
+ break
+ outstream.write(data)
+
+ def check_writable(self, path):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ p = self.translate(path)
+ if os.path.exists(p):
+ remove = 0
+ else:
+ remove = 1
+ f = open(p, 'a') # append mode
+ f.close()
+ if remove:
+ os.remove(p)
+
+ #
+ ############################################################
+
+
+ # utility methods
+
+ def normalize (self, path):
+ # watch for the ever-sneaky '/+' path element
+ # XXX It is unclear why "/+" is dangerous. It is definitely
+ # unexpected.
+ path = re.sub('/+', '/', path)
+ path = os.path.normpath(path)
+ if path.startswith('..'):
+ # Someone is trying to get lower than the permitted root.
+ # We just ignore it.
+ path = os.sep
+ return path
+
+
+ def translate (self, path):
+ """We need to join together three separate path components,
+ and do it safely. <real_root>/<path>
+ use the operating system's path separator.
+
+ We need to be extremly careful to include the cases where a hacker
+ could attempt to a directory below root!
+ """
+ # Normalize the directory
+ path = self.normalize(path)
+ # Prepare for joining with root
+ while path.startswith(os.sep):
+ path = path[1:]
+ # Join path with root
+ return os.path.join(self.root, path)
+
+
+ def __repr__ (self):
+ return '<OSFileSystem, root=%s>' % self.root
+
+
+
+def safe_stat (path):
+ try:
+ return os.stat(path)
+ except:
+ return None
=== Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+import re
+import stat
+import time
+import posixpath
+
+from cStringIO import StringIO
+
+from IReadFileSystem import IReadFileSystem
+from IWriteFileSystem import IWriteFileSystem
+
+from Zope.Publisher.Publish import publish
+
+
+
+class NoOutput:
+ """An output stream lookalike that warns you if you try to
+ dump anything into it."""
+
+ def write(self, data):
+ raise RuntimeError, "Not a writable stream"
+
+ def flush(self):
+ pass
+
+ close = flush
+
+
+
+class PublisherFileSystem:
+ """Generic Publisher FileSystem implementation.
+ """
+
+ __implements__ = IReadFileSystem, IWriteFileSystem
+
+ def __init__ (self, credentials, request_factory):
+ self.credentials = credentials
+ self.request_factory = request_factory
+
+
+ def _execute(self, path, command, env=None):
+ if env is None:
+ env = {}
+
+ env['command'] = command
+ env['path'] = path
+ env['credentials'] = self.credentials
+ # NoOutput avoids creating a black hole.
+ request = self.request_factory(StringIO(''), NoOutput(), env)
+ # Note that publish() calls close() on request, which deletes the
+ # response from the request, so that we need to keep track of it.
+ response = request.getResponse()
+ publish(request)
+ return response.getResult()
+
+
+ ############################################################
+ # Implementation methods for interface
+ # Zope.Server.VFS.IReadFileSystem.
+
+ def exists(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ path = self.translate(path)
+ if path == '/':
+ return 1
+ path, file = posixpath.split(path)
+ env = {'name': file}
+ return self._execute(path, 'exists', env)
+
+
+ def isdir(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ path = self.translate(path)
+ return self._execute(path, 'isdir')
+
+
+ def isfile(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ path = self.translate(path)
+ return self._execute(path, 'isfile')
+
+
+ def listdir(self, path, with_stats=0, pattern='*'):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ path = self.translate(path)
+ env = {'with_stats' : with_stats,
+ 'pattern' : pattern}
+ return self._execute(path, 'listdir', env)
+
+
+ def readfile(self, path, mode, outstream, start=0, end=-1):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ path = self.translate(path)
+ env = {'mode' : mode,
+ 'outstream' : outstream,
+ 'start' : start,
+ 'end' : end}
+ return self._execute(path, 'read', env)
+
+
+ def stat(self, path):
+ 'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
+ path = self.translate(path)
+ return self._execute(path, 'stat')
+
+ #
+ ############################################################
+
+ ############################################################
+ # Implementation methods for interface
+ # Zope.Server.VFS.IWriteFileSystem.
+
+ def mkdir(self, path, mode=777):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ path = self.translate(path)
+ path, dir = posixpath.split(path)
+ env = {'name': dir}
+ return self._execute(path, 'mkdir', env)
+
+
+ def remove(self, path):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ path = self.translate(path)
+ path, name = posixpath.split(path)
+ env = {'name': name}
+ return self._execute(path, 'remove', env)
+
+
+ def rmdir(self, path):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ path = self.translate(path)
+ path, dir = posixpath.split(path)
+ env = {'name': dir}
+ return self._execute(path, 'rmdir', env)
+
+
+ def rename(self, old, new):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ old = self.translate(old)
+ new = self.translate(new)
+ path0, old = posixpath.split(old)
+ path1, new = posixpath.split(new)
+ assert path0 == path1
+ env = {'old' : old,
+ 'new' : new}
+ return self._execute(path0, 'rename', env)
+
+ def writefile(self, path, mode, instream, start=0):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ path = self.translate(path)
+ path, name = posixpath.split(path)
+ env = {'name' : name,
+ 'mode' : mode,
+ 'instream' : instream,
+ 'start' : start}
+ return self._execute(path, 'writefile', env)
+
+
+ def check_writable(self, path):
+ 'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
+ path = self.translate(path)
+ path, name = posixpath.split(path)
+ env = {'name' : name}
+ return self._execute(path, 'check_writable', env)
+
+ #
+ ############################################################
+
+ # utility methods
+
+ def translate (self, path):
+ # Normalize
+ path = posixpath.normpath(path)
+ if path.startswith('..'):
+ # Someone is trying to get lower than the permitted root.
+ # We just ignore it.
+ path = '/'
+ return path
+
=== Zope3/lib/python/Zope/Server/VFS/TestFilesystemAccess.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Implementation of IFilesystemAccess intended only for testing.
+
+$Id$
+"""
+
+from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess
+from Zope.Server.VFS.IUsernamePassword import IUsernamePassword
+from Zope.Exceptions import Unauthorized
+
+
+class TestFilesystemAccess:
+
+ __implements__ = IFilesystemAccess
+
+ passwords = {'foo': 'bar'}
+
+ def __init__(self, fs):
+ self.fs = fs
+
+ def authenticate(self, credentials):
+ if not IUsernamePassword.isImplementedBy(credentials):
+ raise Unauthorized
+ name = credentials.getUserName()
+ if not (name in self.passwords):
+ raise Unauthorized
+ if credentials.getPassword() != self.passwords[name]:
+ raise Unauthorized
+
+ def open(self, credentials):
+ self.authenticate(credentials)
+ return self.fs
+
=== Zope3/lib/python/Zope/Server/VFS/UsernamePassword.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+
+from Zope.Server.VFS.IUsernamePassword import IUsernamePassword
+
+
+class UsernamePassword:
+
+ __implements__ = IUsernamePassword
+
+ def __init__(self, username, password):
+ self.username = username
+ self.password = password
+
+ def getUserName(self):
+ return self.username
+
+ def getPassword(self):
+ return self.password
+
=== Zope3/lib/python/Zope/Server/VFS/__init__.py 1.1 => 1.2 ===
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+