Advertisement
Guest User

Untitled

a guest
May 27th, 2017
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 44.82 KB | None | 0 0
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
  4. #
  5. # This software is subject to the provisions of the Zope Public License,
  6. # Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
  7. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  8. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  9. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  10. # FOR A PARTICULAR PURPOSE
  11. #
  12. ##############################################################################
  13. """Access control package"""
  14.  
  15. __version__='$Revision: 1.182 $'[11:-2]
  16.  
  17. import os
  18.  
  19. import Globals, socket, SpecialUsers,re
  20. from Globals import DTMLFile, MessageDialog, Persistent, PersistentMapping
  21. from App.Management import Navigation, Tabs
  22. from Acquisition import Implicit
  23. from OFS.SimpleItem import Item
  24. from base64 import decodestring
  25. from App.ImageFile import ImageFile
  26. from requestmethod import postonly
  27. from Role import RoleManager, DEFAULTMAXLISTUSERS
  28. from PermissionRole import _what_not_even_god_should_do, rolesForPermissionOn
  29. import AuthEncoding
  30. from AccessControl import getSecurityManager
  31. from zExceptions import Unauthorized, BadRequest
  32. from AccessControl.SecurityManagement import newSecurityManager
  33. from AccessControl.SecurityManagement import noSecurityManager
  34. from AccessControl.ZopeSecurityPolicy import _noroles
  35.  
  36.  
  37. _marker=[]
  38.  
  39. class BasicUser(Implicit):
  40.     """Base class for all User objects"""
  41.  
  42.     # ----------------------------
  43.     # Public User object interface
  44.     # ----------------------------
  45.  
  46.     # Maybe allow access to unprotected attributes. Note that this is
  47.     # temporary to avoid exposing information but without breaking
  48.     # everyone's current code. In the future the security will be
  49.     # clamped down and permission-protected here. Because there are a
  50.     # fair number of user object types out there, this method denies
  51.     # access to names that are private parts of the standard User
  52.     # interface or implementation only. The other approach (only
  53.     # allowing access to public names in the User interface) would
  54.     # probably break a lot of other User implementations with extended
  55.     # functionality that we cant anticipate from the base scaffolding.
  56.     def __allow_access_to_unprotected_subobjects__(self, name, value=None):
  57.         deny_names=('name', '__', 'roles', 'domains', '_getPassword',
  58.                     'authenticate', '_shared_roles')
  59.         if name in deny_names:
  60.             return 0
  61.         return 1
  62.  
  63.     def __init__(self,name,password,roles,domains):
  64.         raise NotImplementedError
  65.  
  66.     def getUserName(self):
  67.         """Return the username of a user"""
  68.         raise NotImplementedError
  69.  
  70.     def getId(self):
  71.         """Get the ID of the user. The ID can be used, at least from
  72.        Python, to get the user from the user's
  73.        UserDatabase"""
  74.         return self.getUserName()
  75.  
  76.     def _getPassword(self):
  77.         """Return the password of the user."""
  78.         raise NotImplementedError
  79.  
  80.     def getRoles(self):
  81.         """Return the list of roles assigned to a user."""
  82.         raise NotImplementedError
  83.  
  84.     def getRolesInContext(self, object):
  85.         """Return the list of roles assigned to the user,
  86.           including local roles assigned in context of
  87.           the passed in object."""
  88.         userid=self.getId()
  89.         roles=self.getRoles()
  90.         local={}
  91.         object=getattr(object, 'aq_inner', object)
  92.         while 1:
  93.             local_roles = getattr(object, '__ac_local_roles__', None)
  94.             if local_roles:
  95.                 if callable(local_roles):
  96.                     local_roles=local_roles()
  97.                 dict=local_roles or {}
  98.                 for r in dict.get(userid, []):
  99.                     local[r]=1
  100.             inner = getattr(object, 'aq_inner', object)
  101.             parent = getattr(inner, 'aq_parent', None)
  102.             if parent is not None:
  103.                 object = parent
  104.                 continue
  105.             if hasattr(object, 'im_self'):
  106.                 object=object.im_self
  107.                 object=getattr(object, 'aq_inner', object)
  108.                 continue
  109.             break
  110.         roles=list(roles) + local.keys()
  111.         return roles
  112.  
  113.     def getDomains(self):
  114.         """Return the list of domain restrictions for a user"""
  115.         raise NotImplementedError
  116.  
  117.     # ------------------------------
  118.     # Internal User object interface
  119.     # ------------------------------
  120.  
  121.     def authenticate(self, password, request):
  122.         passwrd=self._getPassword()
  123.         result = AuthEncoding.pw_validate(passwrd, password)
  124.         domains=self.getDomains()
  125.         if domains:
  126.             return result and domainSpecMatch(domains, request)
  127.         return result
  128.  
  129.  
  130.     def _shared_roles(self, parent):
  131.         r=[]
  132.         while 1:
  133.             if hasattr(parent,'__roles__'):
  134.                 roles=parent.__roles__
  135.                 if roles is None: return 'Anonymous',
  136.                 if 'Shared' in roles:
  137.                     roles=list(roles)
  138.                     roles.remove('Shared')
  139.                     r=r+roles
  140.                 else:
  141.                     try: return r+list(roles)
  142.                     except: return r
  143.             if hasattr(parent, 'aq_parent'):
  144.                 while hasattr(parent.aq_self,'aq_self'):
  145.                     parent=parent.aq_self
  146.                 parent=parent.aq_parent
  147.             else: return r
  148.  
  149.     def _check_context(self, object):
  150.         # Check that 'object' exists in the acquisition context of
  151.         # the parent of the acl_users object containing this user,
  152.         # to prevent "stealing" access through acquisition tricks.
  153.         # Return true if in context, false if not or if context
  154.         # cannot be determined (object is not wrapped).
  155.         parent  = getattr(self, 'aq_parent', None)
  156.         context = getattr(parent, 'aq_parent', None)
  157.         if context is not None:
  158.             if object is None:
  159.                 return 1
  160.             if not hasattr(object, 'aq_inContextOf'):
  161.                 if hasattr(object, 'im_self'):
  162.                     # This is a method.  Grab its self.
  163.                     object=object.im_self
  164.                 if not hasattr(object, 'aq_inContextOf'):
  165.                     # Object is not wrapped, so return false.
  166.                     return 0
  167.             return object.aq_inContextOf(context, 1)
  168.  
  169.         # This is lame, but required to keep existing behavior.
  170.         return 1
  171.  
  172.     def allowed(self, object, object_roles=None):
  173.         """Check whether the user has access to object. The user must
  174.           have one of the roles in object_roles to allow access."""
  175.  
  176.         if object_roles is _what_not_even_god_should_do: return 0
  177.  
  178.         # Short-circuit the common case of anonymous access.
  179.         if object_roles is None or 'Anonymous' in object_roles:
  180.             return 1
  181.  
  182.         # Provide short-cut access if object is protected by 'Authenticated'
  183.         # role and user is not nobody
  184.         if 'Authenticated' in object_roles and (
  185.             self.getUserName() != 'Anonymous User'):
  186.             if self._check_context(object):
  187.                 return 1
  188.  
  189.         # Check for ancient role data up front, convert if found.
  190.         # This should almost never happen, and should probably be
  191.         # deprecated at some point.
  192.         if 'Shared' in object_roles:
  193.             object_roles = self._shared_roles(object)
  194.             if object_roles is None or 'Anonymous' in object_roles:
  195.                 return 1
  196.  
  197.         # Check for a role match with the normal roles given to
  198.         # the user, then with local roles only if necessary. We
  199.         # want to avoid as much overhead as possible.
  200.         user_roles = self.getRoles()
  201.         for role in object_roles:
  202.             if role in user_roles:
  203.                 if self._check_context(object):
  204.                     return 1
  205.                 return None
  206.  
  207.         # Still have not found a match, so check local roles. We do
  208.         # this manually rather than call getRolesInContext so that
  209.         # we can incur only the overhead required to find a match.
  210.         inner_obj = getattr(object, 'aq_inner', object)
  211.         userid = self.getId()
  212.         while 1:
  213.             local_roles = getattr(inner_obj, '__ac_local_roles__', None)
  214.             if local_roles:
  215.                 if callable(local_roles):
  216.                     local_roles = local_roles()
  217.                 dict = local_roles or {}
  218.                 local_roles = dict.get(userid, [])
  219.                 for role in object_roles:
  220.                     if role in local_roles:
  221.                         if self._check_context(object):
  222.                             return 1
  223.                         return 0
  224.             inner = getattr(inner_obj, 'aq_inner', inner_obj)
  225.             parent = getattr(inner, 'aq_parent', None)
  226.             if parent is not None:
  227.                 inner_obj = parent
  228.                 continue
  229.             if hasattr(inner_obj, 'im_self'):
  230.                 inner_obj=inner_obj.im_self
  231.                 inner_obj=getattr(inner_obj, 'aq_inner', inner_obj)
  232.                 continue
  233.             break
  234.         return None
  235.  
  236.     def hasRole(self, *args, **kw):
  237.         """hasRole is an alias for 'allowed' and has been deprecated.
  238.  
  239.        Code still using this method should convert to either 'has_role' or
  240.        'allowed', depending on the intended behaviour.
  241.  
  242.        """
  243.         import warnings
  244.         warnings.warn('BasicUser.hasRole is deprecated, please use '
  245.             'BasicUser.allowed instead; hasRole was an alias for allowed, but '
  246.             'you may have ment to use has_role.', DeprecationWarning)
  247.         return self.allowed(*args, **kw)
  248.  
  249.     domains=[]
  250.  
  251.     def has_role(self, roles, object=None):
  252.         """Check to see if a user has a given role or roles."""
  253.         if isinstance(roles, str):
  254.             roles=[roles]
  255.         if object is not None:
  256.             user_roles = self.getRolesInContext(object)
  257.         else:
  258.             # Global roles only...
  259.             user_roles=self.getRoles()
  260.         for role in roles:
  261.             if role in user_roles:
  262.                 return 1
  263.         return 0
  264.  
  265.     def has_permission(self, permission, object):
  266.         """Check to see if a user has a given permission on an object."""
  267.         roles=rolesForPermissionOn(permission, object)
  268.         if isinstance(roles, str):
  269.             roles=[roles]
  270.         return self.allowed(object, roles)
  271.  
  272.     def __len__(self): return 1
  273.     def __str__(self): return self.getUserName()
  274.     __repr__=__str__
  275.  
  276.  
  277. class SimpleUser(BasicUser):
  278.     """A very simple user implementation
  279.  
  280.    that doesn't make a database commitment"""
  281.  
  282.     def __init__(self,name,password,roles,domains):
  283.         self.name   =name
  284.         self.__     =password
  285.         self.roles  =roles
  286.         self.domains=domains
  287.  
  288.     def getUserName(self):
  289.         """Return the username of a user"""
  290.         return self.name
  291.  
  292.     def _getPassword(self):
  293.         """Return the password of the user."""
  294.         return self.__
  295.  
  296.     def getRoles(self):
  297.         """Return the list of roles assigned to a user."""
  298.         if self.name == 'Anonymous User': return tuple(self.roles)
  299.         else: return tuple(self.roles) + ('Authenticated',)
  300.  
  301.     def getDomains(self):
  302.         """Return the list of domain restrictions for a user"""
  303.         return tuple(self.domains)
  304.  
  305. class SpecialUser(SimpleUser):
  306.     """Class for special users, like emergency user and nobody"""
  307.     def getId(self): pass
  308.  
  309. class User(SimpleUser, Persistent):
  310.     """Standard User object"""
  311.  
  312. class UnrestrictedUser(SpecialUser):
  313.     """User that passes all security checks.  Note, however, that modules
  314.    like Owner.py can still impose restrictions.
  315.    """
  316.     def allowed(self,parent,roles=None):
  317.         return roles is not _what_not_even_god_should_do
  318.  
  319.     def hasRole(self, *args, **kw):
  320.         """hasRole is an alias for 'allowed' and has been deprecated.
  321.  
  322.        Code still using this method should convert to either 'has_role' or
  323.        'allowed', depending on the intended behaviour.
  324.  
  325.        """
  326.         import warnings
  327.         warnings.warn('UnrestrictedUser.hasRole is deprecated, please use '
  328.             'UnrestrictedUser.allowed instead; hasRole was an alias for '
  329.             'allowed, but you may have ment to use has_role.',
  330.             DeprecationWarning)
  331.         self.allowed(*args, **kw)
  332.  
  333.     def has_role(self, roles, object=None): return 1
  334.  
  335.     def has_permission(self, permission, object): return 1
  336.  
  337.  
  338. class NullUnrestrictedUser(SpecialUser):
  339.     """User created if no emergency user exists. It is only around to
  340.       satisfy third party userfolder implementations that may
  341.       expect the emergency user to exist and to be able to call certain
  342.       methods on it (in other words, backward compatibility).
  343.  
  344.       Note that when no emergency user is installed, this object that
  345.       exists in its place is more of an anti-superuser since you cannot
  346.       login as this user and it has no priveleges at all."""
  347.  
  348.     __null_user__=1
  349.  
  350.     def __init__(self):
  351.         pass
  352.  
  353.     def getUserName(self):
  354.         # return an unspellable username
  355.         return (None, None)
  356.     _getPassword=getUserName
  357.  
  358.     def getRoles(self):
  359.         return ()
  360.     getDomains=getRoles
  361.  
  362.     def getRolesInContext(self, object):
  363.         return ()
  364.  
  365.     def authenticate(self, password, request):
  366.         return 0
  367.  
  368.     def allowed(self, parent, roles=None):
  369.         return 0
  370.  
  371.     def hasRole(self, *args, **kw):
  372.         """hasRole is an alias for 'allowed' and has been deprecated.
  373.  
  374.        Code still using this method should convert to either 'has_role' or
  375.        'allowed', depending on the intended behaviour.
  376.  
  377.        """
  378.         import warnings
  379.         warnings.warn('NullUnrestrictedUser.hasRole is deprecated, please use '
  380.             'NullUnrestrictedUser.allowed instead; hasRole was an alias for '
  381.             'allowed, but you may have ment to use has_role.',
  382.             DeprecationWarning)
  383.         self.allowed(*args, **kw)
  384.  
  385.     def has_role(self, roles, object=None):
  386.         return 0
  387.  
  388.     def has_permission(self, permission, object):
  389.         return 0
  390.  
  391.  
  392.  
  393. def readUserAccessFile(filename):
  394.     '''Reads an access file from the instance home.
  395.    Returns name, password, domains, remote_user_mode.
  396.    '''
  397.     import App.config
  398.     cfg = App.config.getConfiguration()
  399.     try:
  400.         f = open(os.path.join(cfg.instancehome, filename), 'r')
  401.         line = f.readline()
  402.         f.close()
  403.     except IOError:
  404.         return None
  405.  
  406.     if line:
  407.         data = line.strip().split(':')
  408.         remote_user_mode = not data[1]
  409.         try:    ds = data[2].split(' ')
  410.         except: ds = []
  411.         return data[0], data[1], ds, remote_user_mode
  412.     else:
  413.         return None
  414.  
  415.  
  416. # Create emergency user.
  417. _remote_user_mode=0
  418.  
  419. info = readUserAccessFile('access')
  420. if info:
  421.     _remote_user_mode = info[3]
  422.     emergency_user = UnrestrictedUser(
  423.         info[0], info[1], ('manage',), info[2])
  424. else:
  425.     emergency_user = NullUnrestrictedUser()
  426.  
  427. super = emergency_user  # Note: use of the 'super' name is deprecated.
  428. del info
  429.  
  430.  
  431. nobody=SpecialUser('Anonymous User','',('Anonymous',), [])
  432. system=UnrestrictedUser('System Processes','',('manage',), [])
  433.  
  434. # stuff these in a handier place for importing
  435. SpecialUsers.nobody=nobody
  436. SpecialUsers.system=system
  437. SpecialUsers.emergency_user=emergency_user
  438. # Note: use of the 'super' name is deprecated.
  439. SpecialUsers.super=emergency_user
  440.  
  441.  
  442. class BasicUserFolder(Implicit, Persistent, Navigation, Tabs, RoleManager,
  443.                       Item):
  444.     """Base class for UserFolder-like objects"""
  445.  
  446.     meta_type='User Folder'
  447.     id       ='acl_users'
  448.     title    ='User Folder'
  449.  
  450.     isPrincipiaFolderish=1
  451.     isAUserFolder=1
  452.     maxlistusers = DEFAULTMAXLISTUSERS
  453.  
  454.     encrypt_passwords = 0
  455.  
  456.     manage_options=(
  457.         (
  458.         {'label':'Contents', 'action':'manage_main',
  459.          'help':('OFSP','User-Folder_Contents.stx')},
  460.         {'label':'Properties', 'action':'manage_userFolderProperties',
  461.          'help':('OFSP','User-Folder_Properties.stx')},
  462.         )
  463.         +RoleManager.manage_options
  464.         +Item.manage_options
  465.         )
  466.  
  467.     __ac_permissions__=(
  468.         ('Manage users',
  469.          ('manage_users','getUserNames', 'getUser', 'getUsers',
  470.           'getUserById', 'user_names', 'setDomainAuthenticationMode',
  471.           'userFolderAddUser', 'userFolderEditUser', 'userFolderDelUsers',
  472.           )
  473.          ),
  474.         )
  475.  
  476.  
  477.     # ----------------------------------
  478.     # Public UserFolder object interface
  479.     # ----------------------------------
  480.  
  481.     def getUserNames(self):
  482.         """Return a list of usernames"""
  483.         raise NotImplementedError
  484.  
  485.     def getUsers(self):
  486.         """Return a list of user objects"""
  487.         raise NotImplementedError
  488.  
  489.     def getUser(self, name):
  490.         """Return the named user object or None"""
  491.         raise NotImplementedError
  492.  
  493.     def getUserById(self, id, default=None):
  494.         """Return the user corresponding to the given id.
  495.        """
  496.         # The connection between getting by ID and by name is not a strong
  497.         # one
  498.         user = self.getUser(id)
  499.         if user is None:
  500.             return default
  501.         return user
  502.  
  503.     def _doAddUser(self, name, password, roles, domains, **kw):
  504.         """Create a new user. This should be implemented by subclasses to
  505.           do the actual adding of a user. The 'password' will be the
  506.           original input password, unencrypted. The implementation of this
  507.           method is responsible for performing any needed encryption."""
  508.         raise NotImplementedError
  509.  
  510.     def _doChangeUser(self, name, password, roles, domains, **kw):
  511.         """Modify an existing user. This should be implemented by subclasses
  512.           to make the actual changes to a user. The 'password' will be the
  513.           original input password, unencrypted. The implementation of this
  514.           method is responsible for performing any needed encryption."""
  515.         raise NotImplementedError
  516.  
  517.     def _doDelUsers(self, names):
  518.         """Delete one or more users. This should be implemented by subclasses
  519.           to do the actual deleting of users."""
  520.         raise NotImplementedError
  521.  
  522.     # As of Zope 2.5, userFolderAddUser, userFolderEditUser and
  523.     # userFolderDelUsers offer aliases for the the _doAddUser, _doChangeUser
  524.     # and _doDelUsers methods (with the difference that they can be called
  525.     # from XML-RPC or untrusted scripting code, given the necessary
  526.     # permissions).
  527.     #
  528.     # Authors of custom user folders don't need to do anything special to
  529.     # support these - they will just call the appropriate '_' methods that
  530.     # user folder subclasses already implement.
  531.     def userFolderAddUser(self, name, password, roles, domains,
  532.                           REQUEST=None, **kw):
  533.         """API method for creating a new user object. Note that not all
  534.           user folder implementations support dynamic creation of user
  535.           objects."""
  536.         if hasattr(self, '_doAddUser'):
  537.             return self._doAddUser(name, password, roles, domains, **kw)
  538.         raise NotImplementedError
  539.     userFolderAddUser = postonly(userFolderAddUser)
  540.  
  541.     def userFolderEditUser(self, name, password, roles, domains,
  542.                            REQUEST=None, **kw):
  543.         """API method for changing user object attributes. Note that not
  544.           all user folder implementations support changing of user object
  545.           attributes."""
  546.         if hasattr(self, '_doChangeUser'):
  547.             return self._doChangeUser(name, password, roles, domains, **kw)
  548.         raise NotImplementedError
  549.     userFolderEditUser = postonly(userFolderEditUser)
  550.  
  551.     def userFolderDelUsers(self, names, REQUEST=None):
  552.         """API method for deleting one or more user objects. Note that not
  553.           all user folder implementations support deletion of user objects."""
  554.         if hasattr(self, '_doDelUsers'):
  555.             return self._doDelUsers(names)
  556.         raise NotImplementedError
  557.     userFolderDelUsers = postonly(userFolderDelUsers)
  558.  
  559.  
  560.     # -----------------------------------
  561.     # Private UserFolder object interface
  562.     # -----------------------------------
  563.  
  564.     _remote_user_mode=_remote_user_mode
  565.     _domain_auth_mode=0
  566.     _emergency_user=emergency_user
  567.     # Note: use of the '_super' name is deprecated.
  568.     _super=emergency_user
  569.     _nobody=nobody
  570.  
  571.  
  572.     def identify(self, auth):
  573.         if auth and auth.lower().startswith('basic '):
  574.             try: name, password=tuple(decodestring(
  575.                                       auth.split(' ')[-1]).split(':', 1))
  576.             except:
  577.                 raise BadRequest, 'Invalid authentication token'
  578.             return name, password
  579.         else:
  580.             return None, None
  581.  
  582.     def authenticate(self, name, password, request):
  583.         emergency = self._emergency_user
  584.         if name is None:
  585.             return None
  586.         if emergency and name==emergency.getUserName():
  587.             user = emergency
  588.         else:
  589.             user = self.getUser(name)
  590.         if user is not None and user.authenticate(password, request):
  591.             return user
  592.         else:
  593.             return None
  594.  
  595.     def authorize(self, user, accessed, container, name, value, roles):
  596.         user = getattr(user, 'aq_base', user).__of__(self)
  597.         newSecurityManager(None, user)
  598.         security = getSecurityManager()
  599.         try:
  600.             try:
  601.                 # This is evil: we cannot pass _noroles directly because
  602.                 # it is a special marker, and that special marker is not
  603.                 # the same between the C and Python policy implementations.
  604.                 # We __really__ need to stop using this marker pattern!
  605.                 if roles is _noroles:
  606.                     if security.validate(accessed, container, name, value):
  607.                         return 1
  608.                 else:
  609.                     if security.validate(accessed, container, name, value,
  610.                                          roles):
  611.                         return 1
  612.             except:
  613.                 noSecurityManager()
  614.                 raise
  615.         except Unauthorized: pass
  616.         return 0
  617.  
  618.     def validate(self, request, auth='', roles=_noroles):
  619.         """
  620.        this method performs identification, authentication, and
  621.        authorization
  622.        v is the object (value) we're validating access to
  623.        n is the name used to access the object
  624.        a is the object the object was accessed through
  625.        c is the physical container of the object
  626.  
  627.        We allow the publishing machinery to defer to higher-level user
  628.        folders or to raise an unauthorized by returning None from this
  629.        method.
  630.        """
  631.         v = request['PUBLISHED'] # the published object
  632.         a, c, n, v = self._getobcontext(v, request)
  633.  
  634.         # we need to continue to support this silly mode
  635.         # where if there is no auth info, but if a user in our
  636.         # database has no password and he has domain restrictions,
  637.         # return him as the authorized user.
  638.         if not auth:
  639.             if self._domain_auth_mode:
  640.                 for user in self.getUsers():
  641.                     if user.getDomains():
  642.                         if self.authenticate(user.getUserName(), '', request):
  643.                             if self.authorize(user, a, c, n, v, roles):
  644.                                 return user.__of__(self)
  645.  
  646.         name, password = self.identify(auth)
  647.         user = self.authenticate(name, password, request)
  648.         # user will be None if we can't authenticate him or if we can't find
  649.         # his username in this user database.
  650.         emergency = self._emergency_user
  651.         if emergency and user is emergency:
  652.             if self._isTop():
  653.                 # we do not need to authorize the emergency user against the
  654.                 # published object.
  655.                 return emergency.__of__(self)
  656.             else:
  657.                 # we're not the top-level user folder
  658.                 return None
  659.         elif user is None:
  660.             # either we didn't find the username, or the user's password
  661.             # was incorrect.  try to authorize and return the anonymous user.
  662.             if self._isTop() and self.authorize(self._nobody, a,c,n,v,roles):
  663.                 return self._nobody.__of__(self)
  664.             else:
  665.                 # anonymous can't authorize or we're not top-level user folder
  666.                 return None
  667.         else:
  668.             # We found a user, his password was correct, and the user
  669.             # wasn't the emergency user.  We need to authorize the user
  670.             # against the published object.
  671.             if self.authorize(user, a, c, n, v, roles):
  672.                 return user.__of__(self)
  673.             # That didn't work.  Try to authorize the anonymous user.
  674.             elif self._isTop() and self.authorize(self._nobody,a,c,n,v,roles):
  675.                 return self._nobody.__of__(self)
  676.             else:
  677.                 # we can't authorize the user, and we either can't authorize
  678.                 # nobody against the published object or we're not top-level
  679.                 return None
  680.  
  681.     if _remote_user_mode:
  682.  
  683.         def validate(self, request, auth='', roles=_noroles):
  684.             v = request['PUBLISHED']
  685.             a, c, n, v = self._getobcontext(v, request)
  686.             name = request.environ.get('REMOTE_USER', None)
  687.             if name is None:
  688.                 if self._domain_auth_mode:
  689.                     for user in self.getUsers():
  690.                         if user.getDomains():
  691.                             if self.authenticate(
  692.                                 user.getUserName(), '', request
  693.                                 ):
  694.                                 if self.authorize(user, a, c, n, v, roles):
  695.                                     return user.__of__(self)
  696.  
  697.             user = self.getUser(name)
  698.             # user will be None if we can't find his username in this user
  699.             # database.
  700.             emergency = self._emergency_user
  701.             if emergency and name==emergency.getUserName():
  702.                 if self._isTop():
  703.                     # we do not need to authorize the emergency user against
  704.                     #the published object.
  705.                     return emergency.__of__(self)
  706.                 else:
  707.                     # we're not the top-level user folder
  708.                     return None
  709.             elif user is None:
  710.                 # we didn't find the username in this database
  711.                 # try to authorize and return the anonymous user.
  712.                 if self._isTop() and self.authorize(self._nobody,
  713.                                                     a, c, n, v, roles):
  714.                     return self._nobody.__of__(self)
  715.                 else:
  716.                     # anonymous can't authorize or we're not top-level user
  717.                     # folder
  718.                     return None
  719.             else:
  720.                 # We found a user and the user wasn't the emergency user.
  721.                 # We need to authorize the user against the published object.
  722.                 if self.authorize(user, a, c, n, v, roles):
  723.                     return user.__of__(self)
  724.                 # That didn't work.  Try to authorize the anonymous user.
  725.                 elif self._isTop() and self.authorize(
  726.                     self._nobody, a, c, n, v, roles):
  727.                     return self._nobody.__of__(self)
  728.                 else:
  729.                     # we can't authorize the user, and we either can't
  730.                     # authorize nobody against the published object or
  731.                     # we're not top-level
  732.                     return None
  733.  
  734.     def _getobcontext(self, v, request):
  735.         """
  736.        v is the object (value) we're validating access to
  737.        n is the name used to access the object
  738.        a is the object the object was accessed through
  739.        c is the physical container of the object
  740.        """
  741.         if len(request.steps) == 0: # someone deleted root index_html
  742.             request.RESPONSE.notFoundError('no default view (root default view'
  743.                                            ' was probably deleted)')
  744.         n = request.steps[-1]
  745.         # default to accessed and container as v.aq_parent
  746.         a = c = request['PARENTS'][0]
  747.         # try to find actual container
  748.         inner = getattr(v, 'aq_inner', v)
  749.         innerparent = getattr(inner, 'aq_parent', None)
  750.         if innerparent is not None:
  751.             # this is not a method, we needn't treat it specially
  752.             c = innerparent
  753.         elif hasattr(v, 'im_self'):
  754.             # this is a method, we need to treat it specially
  755.             c = v.im_self
  756.             c = getattr(v, 'aq_inner', v)
  757.         request_container = getattr(request['PARENTS'][-1], 'aq_parent', [])
  758.         # if pub's aq_parent or container is the request container, it
  759.         # means pub was accessed from the root
  760.         if a is request_container:
  761.             a = request['PARENTS'][-1]
  762.         if c is request_container:
  763.             c = request['PARENTS'][-1]
  764.  
  765.         return a, c, n, v
  766.  
  767.     def _isTop(self):
  768.         try:
  769.             return self.aq_parent.aq_base.isTopLevelPrincipiaApplicationObject
  770.         except:
  771.             return 0
  772.  
  773.     def __len__(self):
  774.         return 1
  775.  
  776.     _mainUser=DTMLFile('dtml/mainUser', globals())
  777.     _add_User=DTMLFile('dtml/addUser', globals(),
  778.                        remote_user_mode__=_remote_user_mode)
  779.     _editUser=DTMLFile('dtml/editUser', globals(),
  780.                        remote_user_mode__=_remote_user_mode)
  781.     manage=manage_main=_mainUser
  782.     manage_main._setName('manage_main')
  783.  
  784.     _userFolderProperties = DTMLFile('dtml/userFolderProps', globals())
  785.  
  786.     def manage_userFolderProperties(self, REQUEST=None,
  787.                                     manage_tabs_message=None):
  788.         """
  789.        """
  790.         return self._userFolderProperties(
  791.             self, REQUEST, manage_tabs_message=manage_tabs_message,
  792.             management_view='Properties')
  793.  
  794.     def manage_setUserFolderProperties(self, encrypt_passwords=0,
  795.                                        update_passwords=0,
  796.                                        maxlistusers=DEFAULTMAXLISTUSERS,
  797.                                        REQUEST=None):
  798.         """
  799.        Sets the properties of the user folder.
  800.        """
  801.         self.encrypt_passwords = not not encrypt_passwords
  802.         try:
  803.             self.maxlistusers = int(maxlistusers)
  804.         except ValueError:
  805.             self.maxlistusers = DEFAULTMAXLISTUSERS
  806.         if encrypt_passwords and update_passwords:
  807.             changed = 0
  808.             for u in self.getUsers():
  809.                 pw = u._getPassword()
  810.                 if not self._isPasswordEncrypted(pw):
  811.                     pw = self._encryptPassword(pw)
  812.                     self._doChangeUser(u.getUserName(), pw, u.getRoles(),
  813.                                        u.getDomains())
  814.                     changed = changed + 1
  815.             if REQUEST is not None:
  816.                 if not changed:
  817.                     msg = 'All passwords already encrypted.'
  818.                 else:
  819.                     msg = 'Encrypted %d password(s).' % changed
  820.                 return self.manage_userFolderProperties(
  821.                     REQUEST, manage_tabs_message=msg)
  822.             else:
  823.                 return changed
  824.         else:
  825.             if REQUEST is not None:
  826.                 return self.manage_userFolderProperties(
  827.                     REQUEST, manage_tabs_message='Saved changes.')
  828.     manage_setUserFolderProperties = postonly(manage_setUserFolderProperties)
  829.  
  830.     def _isPasswordEncrypted(self, pw):
  831.         return AuthEncoding.is_encrypted(pw)
  832.  
  833.     def _encryptPassword(self, pw):
  834.         return AuthEncoding.pw_encrypt(pw, 'SSHA')
  835.  
  836.  
  837.     def domainSpecValidate(self,spec):
  838.  
  839.         for ob in spec:
  840.  
  841.             am = addr_match(ob)
  842.             hm = host_match(ob)
  843.  
  844.             if am is None and hm is None:
  845.                 return 0
  846.  
  847.         return 1
  848.  
  849.     def _addUser(self,name,password,confirm,roles,domains,REQUEST=None):
  850.         if not name:
  851.             return MessageDialog(
  852.                    title  ='Illegal value',
  853.                    message='A username must be specified',
  854.                    action ='manage_main')
  855.         if not password or not confirm:
  856.             if not domains:
  857.                 return MessageDialog(
  858.                    title  ='Illegal value',
  859.                    message='Password and confirmation must be specified',
  860.                    action ='manage_main')
  861.         if self.getUser(name) or (self._emergency_user and
  862.                                   name == self._emergency_user.getUserName()):
  863.             return MessageDialog(
  864.                    title  ='Illegal value',
  865.                    message='A user with the specified name already exists',
  866.                    action ='manage_main')
  867.         if (password or confirm) and (password != confirm):
  868.             return MessageDialog(
  869.                    title  ='Illegal value',
  870.                    message='Password and confirmation do not match',
  871.                    action ='manage_main')
  872.  
  873.         if not roles: roles=[]
  874.         if not domains: domains=[]
  875.  
  876.         if domains and not self.domainSpecValidate(domains):
  877.             return MessageDialog(
  878.                    title  ='Illegal value',
  879.                    message='Illegal domain specification',
  880.                    action ='manage_main')
  881.         self._doAddUser(name, password, roles, domains)
  882.         if REQUEST: return self._mainUser(self, REQUEST)
  883.     _addUser = postonly(_addUser)
  884.  
  885.     def _changeUser(self,name,password,confirm,roles,domains,REQUEST=None):
  886.         if password == 'password' and confirm == 'pconfirm':
  887.             # Protocol for editUser.dtml to indicate unchanged password
  888.             password = confirm = None
  889.         if not name:
  890.             return MessageDialog(
  891.                    title  ='Illegal value',
  892.                    message='A username must be specified',
  893.                    action ='manage_main')
  894.         if password == confirm == '':
  895.             if not domains:
  896.                 return MessageDialog(
  897.                    title  ='Illegal value',
  898.                    message='Password and confirmation must be specified',
  899.                    action ='manage_main')
  900.         if not self.getUser(name):
  901.             return MessageDialog(
  902.                    title  ='Illegal value',
  903.                    message='Unknown user',
  904.                    action ='manage_main')
  905.         if (password or confirm) and (password != confirm):
  906.             return MessageDialog(
  907.                    title  ='Illegal value',
  908.                    message='Password and confirmation do not match',
  909.                    action ='manage_main')
  910.  
  911.         if not roles: roles=[]
  912.         if not domains: domains=[]
  913.  
  914.         if domains and not self.domainSpecValidate(domains):
  915.             return MessageDialog(
  916.                    title  ='Illegal value',
  917.                    message='Illegal domain specification',
  918.                    action ='manage_main')
  919.         self._doChangeUser(name, password, roles, domains)
  920.         if REQUEST: return self._mainUser(self, REQUEST)
  921.     _changeUser = postonly(_changeUser)
  922.  
  923.     def _delUsers(self,names,REQUEST=None):
  924.         if not names:
  925.             return MessageDialog(
  926.                    title  ='Illegal value',
  927.                    message='No users specified',
  928.                    action ='manage_main')
  929.         self._doDelUsers(names)
  930.         if REQUEST: return self._mainUser(self, REQUEST)
  931.     _delUsers = postonly(_delUsers)
  932.  
  933.     def manage_users(self,submit=None,REQUEST=None,RESPONSE=None):
  934.         """This method handles operations on users for the web based forms
  935.           of the ZMI. Application code (code that is outside of the forms
  936.           that implement the UI of a user folder) are encouraged to use
  937.           manage_std_addUser"""
  938.         if submit=='Add...':
  939.             return self._add_User(self, REQUEST)
  940.  
  941.         if submit=='Edit':
  942.             try:    user=self.getUser(reqattr(REQUEST, 'name'))
  943.             except: return MessageDialog(
  944.                     title  ='Illegal value',
  945.                     message='The specified user does not exist',
  946.                     action ='manage_main')
  947.             return self._editUser(self,REQUEST,user=user,password=user.__)
  948.  
  949.         if submit=='Add':
  950.             name    =reqattr(REQUEST, 'name')
  951.             password=reqattr(REQUEST, 'password')
  952.             confirm =reqattr(REQUEST, 'confirm')
  953.             roles   =reqattr(REQUEST, 'roles')
  954.             domains =reqattr(REQUEST, 'domains')
  955.             return self._addUser(name,password,confirm,roles,domains,REQUEST)
  956.  
  957.         if submit=='Change':
  958.             name    =reqattr(REQUEST, 'name')
  959.             password=reqattr(REQUEST, 'password')
  960.             confirm =reqattr(REQUEST, 'confirm')
  961.             roles   =reqattr(REQUEST, 'roles')
  962.             domains =reqattr(REQUEST, 'domains')
  963.             return self._changeUser(name,password,confirm,roles,
  964.                                     domains,REQUEST)
  965.  
  966.         if submit=='Delete':
  967.             names=reqattr(REQUEST, 'names')
  968.             return self._delUsers(names,REQUEST)
  969.  
  970.         return self._mainUser(self, REQUEST)
  971.  
  972.     def user_names(self):
  973.         return self.getUserNames()
  974.  
  975.     def manage_beforeDelete(self, item, container):
  976.         if item is self:
  977.             try: del container.__allow_groups__
  978.             except: pass
  979.  
  980.     def manage_afterAdd(self, item, container):
  981.         if item is self:
  982.             if hasattr(self, 'aq_base'): self=self.aq_base
  983.             container.__allow_groups__=self
  984.  
  985.     def __creatable_by_emergency_user__(self): return 1
  986.    def _setId(self, id):
  987.         if id != self.id:
  988.             raise Globals.MessageDialog(
  989.                 title='Invalid Id',
  990.                 message='Cannot change the id of a UserFolder',
  991.                 action ='./manage_main',)
  992.  
  993.  
  994.     # Domain authentication support. This is a good candidate to
  995.     # become deprecated in future Zope versions.
  996.  
  997.     def setDomainAuthenticationMode(self, domain_auth_mode):
  998.         """Set the domain-based authentication mode. By default, this
  999.           mode is off due to the high overhead of the operation that
  1000.           is incurred for all anonymous accesses. If you have the
  1001.           'Manage Users' permission, you can call this method via
  1002.           the web, passing a boolean value for domain_auth_mode to
  1003.           turn this behavior on or off."""
  1004.         v = self._domain_auth_mode = domain_auth_mode and 1 or 0
  1005.         return 'Domain authentication mode set to %d' % v
  1006.  
  1007.     def domainAuthModeEnabled(self):
  1008.         """ returns true if domain auth mode is set to true"""
  1009.         return getattr(self, '_domain_auth_mode', None)
  1010.  
  1011. class UserFolder(BasicUserFolder):
  1012.     """Standard UserFolder object
  1013.  
  1014.    A UserFolder holds User objects which contain information
  1015.    about users including name, password domain, and roles.
  1016.    UserFolders function chiefly to control access by authenticating
  1017.    users and binding them to a collection of roles."""
  1018.  
  1019.     meta_type='User Folder'
  1020.     id       ='acl_users'
  1021.     title    ='User Folder'
  1022.     icon     ='p_/UserFolder'
  1023.  
  1024.     def __init__(self):
  1025.         self.data=PersistentMapping()
  1026.  
  1027.     def getUserNames(self):
  1028.         """Return a list of usernames"""
  1029.         names=self.data.keys()
  1030.         names.sort()
  1031.         return names
  1032.  
  1033.     def getUsers(self):
  1034.         """Return a list of user objects"""
  1035.         data=self.data
  1036.         names=data.keys()
  1037.         names.sort()
  1038.         return [data[n] for n in names]
  1039.  
  1040.     def getUser(self, name):
  1041.         """Return the named user object or None"""
  1042.         return self.data.get(name, None)
  1043.  
  1044.     def hasUsers(self):
  1045.         """ This is not a formal API method: it is used only to provide
  1046.        a way for the quickstart page to determine if the default user
  1047.        folder contains any users to provide instructions on how to
  1048.        add a user for newbies.  Using getUserNames or getUsers would have
  1049.        posed a denial of service risk."""
  1050.         return not not len(self.data)
  1051.  
  1052.     def _doAddUser(self, name, password, roles, domains, **kw):
  1053.         """Create a new user"""
  1054.         if password is not None and self.encrypt_passwords \
  1055.                                 and not self._isPasswordEncrypted(password):
  1056.             password = self._encryptPassword(password)
  1057.         self.data[name]=User(name,password,roles,domains)
  1058.  
  1059.     def _doChangeUser(self, name, password, roles, domains, **kw):
  1060.         user=self.data[name]
  1061.         if password is not None:
  1062.             if (  self.encrypt_passwords
  1063.                   and not self._isPasswordEncrypted(password)):
  1064.                 password = self._encryptPassword(password)
  1065.             user.__=password
  1066.         user.roles=roles
  1067.         user.domains=domains
  1068.  
  1069.     def _doDelUsers(self, names):
  1070.         for name in names:
  1071.             del self.data[name]
  1072.  
  1073.     def _createInitialUser(self):
  1074.         """
  1075.        If there are no users or only one user in this user folder,
  1076.        populates from the 'inituser' file in the instance home.
  1077.        We have to do this even when there is already a user
  1078.        just in case the initial user ignored the setup messages.
  1079.        We don't do it for more than one user to avoid
  1080.        abuse of this mechanism.
  1081.        Called only by OFS.Application.initialize().
  1082.        """
  1083.         if len(self.data) <= 1:
  1084.             info = readUserAccessFile('inituser')
  1085.             if info:
  1086.                 import App.config
  1087.                 name, password, domains, remote_user_mode = info
  1088.                 self._doDelUsers(self.getUserNames())
  1089.                 self._doAddUser(name, password, ('Manager',), domains)
  1090.                 cfg = App.config.getConfiguration()
  1091.                 try:
  1092.                     os.remove(os.path.join(cfg.instancehome, 'inituser'))
  1093.                 except:
  1094.                     pass
  1095.  
  1096.  
  1097. Globals.default__class_init__(UserFolder)
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104. def manage_addUserFolder(self,dtself=None,REQUEST=None,**ignored):
  1105.     """ """
  1106.     f=UserFolder()
  1107.     self=self.this()
  1108.     try:    self._setObject('acl_users', f)
  1109.     except: return MessageDialog(
  1110.                    title  ='Item Exists',
  1111.                    message='This object already contains a User Folder',
  1112.                    action ='%s/manage_main' % REQUEST['URL1'])
  1113.     self.__allow_groups__=f
  1114.     if REQUEST is not None:
  1115.         REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
  1116.  
  1117.  
  1118. def rolejoin(roles, other):
  1119.     dict={}
  1120.     for role in roles:
  1121.         dict[role]=1
  1122.     for role in other:
  1123.         dict[role]=1
  1124.     roles=dict.keys()
  1125.     roles.sort()
  1126.     return roles
  1127.  
  1128. addr_match=re.compile(r'((\d{1,3}\.){1,3}\*)|((\d{1,3}\.){3}\d{1,3})').match
  1129. host_match=re.compile(r'(([\_0-9a-zA-Z\-]*\.)*[0-9a-zA-Z\-]*)').match
  1130.  
  1131.  
  1132.  
  1133. def domainSpecMatch(spec, request):
  1134.     host=''
  1135.     addr=''
  1136.  
  1137.     # Fast exit for the match-all case
  1138.     if len(spec) == 1 and spec[0] == '*':
  1139.         return 1
  1140.  
  1141.     if request.has_key('REMOTE_HOST'):
  1142.         host=request['REMOTE_HOST']
  1143.  
  1144.     addr=request.getClientAddr()
  1145.  
  1146.     if not host and not addr:
  1147.         return 0
  1148.  
  1149.     if not host:
  1150.         try:    host=socket.gethostbyaddr(addr)[0]
  1151.         except: pass
  1152.     if not addr:
  1153.         try:    addr=socket.gethostbyname(host)
  1154.         except: pass
  1155.  
  1156.  
  1157.     _host=host.split('.')
  1158.     _addr=addr.split('.')
  1159.     _hlen=len(_host)
  1160.     _alen=len(_addr)
  1161.  
  1162.     for ob in spec:
  1163.         sz=len(ob)
  1164.         _ob=ob.split('.')
  1165.         _sz=len(_ob)
  1166.  
  1167.         mo = addr_match(ob)
  1168.         if mo is not None:
  1169.             if mo.end(0)==sz:
  1170.                 fail=0
  1171.                 for i in range(_sz):
  1172.                     a=_addr[i]
  1173.                     o=_ob[i]
  1174.                     if (o != a) and (o != '*'):
  1175.                         fail=1
  1176.                         break
  1177.                 if fail:
  1178.                     continue
  1179.                 return 1
  1180.  
  1181.         mo = host_match(ob)
  1182.         if mo is not None:
  1183.             if mo.end(0)==sz:
  1184.                 if _hlen < _sz:
  1185.                     continue
  1186.                 elif _hlen > _sz:
  1187.                     _item=_host[-_sz:]
  1188.                 else:
  1189.                     _item=_host
  1190.                 fail=0
  1191.                 for i in range(_sz):
  1192.                     h=_item[i]
  1193.                     o=_ob[i]
  1194.                     if (o != h) and (o != '*'):
  1195.                         fail=1
  1196.                         break
  1197.                 if fail:
  1198.                     continue
  1199.                 return 1
  1200.     return 0
  1201.  
  1202.  
  1203. def absattr(attr):
  1204.     if callable(attr): return attr()
  1205.     return attr
  1206.  
  1207. def reqattr(request, attr):
  1208.     try:    return request[attr]
  1209.     except: return None
  1210.  
  1211. Super = UnrestrictedUser  # Note: use of the Super alias is deprecated.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement