[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$
+"""
+