Logo Search packages:      
Sourcecode: zope-loginmanager version File versions

LoginManager.py

from OFS.Folder import Folder
from OFS.SimpleItem import Item
from OFS.PropertyManager import PropertyManager
from AccessControl.User import User, super, nobody
from AccessControl.PermissionRole import _what_not_even_god_should_do
from Globals import HTMLFile, MessageDialog
from Products.PlugIns import PlugInGroup, PlugInFinder, MakePICBase
from Products.ZPatterns.Specialists import Specialist
from Products.ZPatterns.DataManagers import DataManager

_LoggingInUser = User('LoggingInUser', '', ['LoggingIn'], [])

# Support Zope-2.2a1 onwership foo
try:
    from AccessControl.Owned import UnownableOwner
except ImportError:
    UnownableOwner=None


##################### Local Roles Patch #####################

def get_local_roles_for_userid(self, userid, roles=()):
     dict=self.__ac_local_roles__ or {}
     return dict.get(userid, [])

def get_local_roles_for_user(self, user, roles=()):
    return self.get_local_roles_for_userid(user.getUserName(),roles)

from AccessControl.Role import RoleManager
RoleManager.get_local_roles_for_userid = get_local_roles_for_userid
RoleManager.get_local_roles_for_user = get_local_roles_for_user

class BetterLocalRolesMixin:
     def getRolesInContext(self, object, findRoles=()):
         """Return the list of roles assigned to the user,
            including local roles assigned in context of
            the passed in object.  If asked to find specific
            roles, return true if any of the specified roles
            is found, false otherwise.
         """
 
         roles=self.getRoles()
         for r in findRoles:
             if r in roles: return roles
 
         local={}
         object=getattr(object, 'aq_inner', object)
 
         while 1:
             if hasattr(object, 'get_local_roles_for_user'):
                 for r in object.get_local_roles_for_user(self):
                     local[r]=1
                     if r in findRoles: return list(roles)+local.keys()
 
             if hasattr(object, 'aq_parent'):
                 object=object.aq_parent
                 continue
             if hasattr(object, 'im_self'):
                 object=object.im_self
                 object=getattr(object, 'aq_inner', object)
                 continue
             break
 
         if findRoles: return ()
 
         roles=list(roles) + local.keys()
         return roles
 
     def allowed(self, parent, roles=None):
         """Check whether the user has access to parent, assuming that
            parent.__roles__ is the given roles."""
 
         if roles is None or 'Anonymous' in roles:
             return 1
 
         if self.getRolesInContext(parent,roles):
             if (hasattr(self,'aq_parent') and
                 hasattr(self.aq_parent,'aq_parent')):
                 if parent is None: return 1
                 if (not hasattr(parent, 'aq_inContextOf') and
                     hasattr(parent, 'im_self')):
                     # This is a method, grab it's self.
                     parent=parent.im_self
                 if not parent.aq_inContextOf(self.aq_parent.aq_parent,1):
                     if 'Shared' in roles:
                         # Damn, old role setting. Waaa
                         roles=self._shared_roles(parent)
                         if 'Anonymous' in roles: return 1
                     return None
             return 1
 
         if 'Shared' in roles:
             # Damn, old role setting. Waaa
             roles=self._shared_roles(parent)
             if roles is None or 'Anonymous' in roles: return 1
             while 'Shared' in roles: roles.remove('Shared')
             return self.allowed(parent,roles)
 
         return None
 
     hasRole=allowed

from AccessControl.User import SimpleUser

class BetterSimpleUser(BetterLocalRolesMixin, SimpleUser):
    pass

#############################################################

#################### Multiple Root Users ####################
try:
    from AccessControl.SpecialUsers import rootUsers
except:
    from AccessControl.User import _remote_user_mode, Super
    from string import strip, split
    import AccessControl.SpecialUsers

    try:
        f=open('%s/access' % INSTANCE_HOME, 'r')
    except IOError:
        raise 'InstallError', (
            'No access file found at %s - see INSTALL.txt' % INSTANCE_HOME
            )
    try:
        d=f.readlines(); f.close(); del f
        rootUsers = AccessControl.SpecialUsers.rootUsers = {}

        for data in map(strip,d):
            if not data or data[0]=='#': continue
            data=split(data+':::',':')     # allow for missing fields

            n = data[0]
            ds = split(strip(data[2])) # space-delimited domains
            pw = data[1]
            r  = split(strip(data[3])) # space-delimited roles

            if rootUsers or r:
                # If not first user in file, or if roles are specified,
                # user is a "normal" user object
                rootUsers[n] = BetterSimpleUser(n,data[1],tuple(split(data[3])),data[2])
            else:
                super = rootUsers[n] = Super(n,pw,('manage',), ds)
                _remote_user_mode=not pw
    
            del data,n,ds,pw,r

        del d

    except:
        raise 'InstallError', 'Invalid format for access file - see INSTALL.txt'
    
#############################################################

# Convenient singleton used by LoginManager as default login method
from LoginMethods import BasicAuth
_DefaultAuth = BasicAuth('default', '')


# Waaaaaaa!

from ZPublisher.BaseRequest import BaseRequest
oldclose = BaseRequest.close.im_func

def close(self,oldclose=oldclose):
    try: del self.response.unauthorized
    except: pass
    oldclose(self)

BaseRequest.close = close




00174 class LoginManager(Specialist):
    """Thing that manages LoginMethods and UserSources"""

    _owner = UnownableOwner

    def __init__(self):
        self.userSourcesList = []
        self.loginMethodsList = []

    # Public UserFolder object interface

    def getItem(self,name):
        # Retrieve a user with the given name, or None if no such
        # user exists. Uses the registry of UserSources, after
        # first checking for the superusSer/root users.

        if rootUsers.has_key(name):
            return rootUsers[name].__of__(self)

        for source in self.userSourcesList:
            user = source.__of__(self).getItem(name)
            if user is not None:
                return user

        return None

    getUser = getItem

    def getUserById(self, id, default=None):
        u = self.getItem(id)
        if u is None:
            u = default
        return u
            
    def credentialsChanged(self, user, name, credentials):
        for mname in self.REQUEST.LOGIN_METHODS:
            loginMethod=getattr(self,mname)
            loginMethod.credentialsChanged(self, user, name, credentials)

    def logoutUser(self,name):
        if self.REQUEST.AUTHENTICATED_USER.getUserName()==name:
            for mname in self.REQUEST.LOGIN_METHODS:
                loginMethod=getattr(self,mname)
                loginMethod.logoutCurrentUser(self, name)





    def validate(self, request, auth='', roles=None):
        request.set('LOGIN_METHODS',[])
        if roles is _what_not_even_god_should_do:
            request.response.notFoundError()

        parents=request.get('PARENTS', [])
        if not parents: parent=self.aq_parent
        else:           parent=parents[0]

        request['AUTHENTICATED_USER'] = _LoggingInUser
        user = None; response=request.response

        if self.loginMethodsList:
            for loginMethod in self.loginMethodsList:
                user = loginMethod.findLogin(self, request, auth, user, roles)
        else:   # default to BasicAuth if no login methods
            user = _DefaultAuth.findLogin(self, request, auth, user, roles)

        if user is not None:
            # We got a user, check him out
            user=getattr(user,'aq_base',user).__of__(self)
            if user.allowed(parent, roles): return user

            # Give the app a chance to tell the user he's logged
            # in, but not allowed
            if hasattr(self,'forbiddenPage'):
                if response.unauthorized.__name__=='unauthorized':

                    def lm_unauth(lm=self,request=request,user=user,roles=roles,old=response.unauthorized):
                        request['AUTHENTICATED_USER'] = user
                        lm.forbiddenPage(lm, request, needroles=roles)

                        if hasattr(lm,'loginForm'):
                            lm.loginForm(lm, request, needroles=roles)

                        old()

                    response.unauthorized = lm_unauth

                return None  # give higher acl_users a chance to okay the user

        elif self._isTop():   # Fall back to anonymous
            user = self._nobody
            if user.allowed(parent, roles): return user

        # And if anonymous doesn't work (or forbiddenPage
        # doesn't make a fuss), then make 'em log in!
        # (or fall back to higher level user folders)
        if hasattr(self,'loginForm') and \
            response.unauthorized.__name__=='unauthorized':

            def lm_unauth(lm=self,request=request,roles=roles,old=response.unauthorized):
                lm.loginForm(lm, request, needroles=roles)
                old()

            response.unauthorized = lm_unauth

    ### SimpleItem Protocol ###

    def manage_beforeDelete(self,item,container):
        Folder.manage_beforeDelete(self,item,container)
        if item is self:
            try: del container.__allow_groups__
            except: pass

    def manage_afterAdd(self,item,container):
        Folder.manage_afterAdd(self,item,container)
        if item is self:
            if hasattr(self, 'aq_base'): self=self.aq_base
            container.__allow_groups__=self

    def _setId(self, id):
        if id != self.id:
            raise 'Rename Error', MessageDialog(
                title='Invalid Id',
                message='Cannot change the id of a LoginManager',
                action ='./manage_main',)

    def _isTop(self):
        try: return self.aq_parent.aq_base.isTopLevelPrincipiaApplicationObject
        except: return 0

    # Class Metadata

    meta_type = 'Login Manager'
    id = 'acl_users'
    title = 'Login Manager'

    __ac_roles__ = ('LoggingIn',)

    _nobody = nobody

    UserSourcesGroup = PlugInGroup('UserSourcesGroup',['User Source'],
        attr='userSourcesList', title='User Sources')
        
    LoginMethodsGroup = PlugInGroup('LoginMethodsGroup',['Login Method'],
        attr='loginMethodsList', title='Login Methods')

    __plugin_groups__ = (UserSourcesGroup, LoginMethodsGroup) + \
        DataManager.__plugin_groups__

    def __creatable_by_super__(self): return 1
    
    # Would be nice if we had a "manage users" tab which would
    # emulate the standard zopish user folder by delegating to the
    # user sources, or could at least refer the operator to the interfaces
    # of the subordinate user sources

    # XXX No need for default__class_init__ or __ac_permissions__ unless 
    # we later override base class methods or add new functionality.

MakePICBase(LoginManager)

manage_addLoginManagerForm = HTMLFile('addLoginManager', globals(),
    UserSourcesMetaTypes = PlugInFinder(LoginManager.UserSourcesGroup),
    LoginMethodsMetaTypes = PlugInFinder(LoginManager.LoginMethodsGroup))








def manage_addLoginManager(self,
    usource=None, lmeths=[], loginf=1, logoutf=1, forbidp=1,
    REQUEST=None):

    """Add a LoginManager to the self folder"""

    ob = LoginManager()

    self._setObject('acl_users', ob)
    self.__allow_groups__ = ob

    # Now create default objects

    ob = self.__allow_groups__ 

    ob.UserSourcesGroup._constructPlugIn(usource, id='UserSource')

    for lm in lmeths:
        ob.LoginMethodsGroup._constructPlugIn(lm)

    if loginf:
        ob.manage_addDTMLDocument(id='loginForm', file=defLoginForm)

    if logoutf:
        ob.manage_addDTMLDocument(id='logoutForm', file=defLogoutForm)

    if forbidp:
        ob.manage_addDTMLDocument(id='forbiddenPage', file=defForbiddenPage)

    # Success!
    if REQUEST: return self.manage_main(self,REQUEST,update_menu=1)










# Default DTML Documents

defLoginForm = """<dtml-raise "'LoginRequired'"><html>
<head><title>Please log in.</title></head>
<body bgcolor="ffffff">
<br>

<dtml-comment>
  This login form is appropriate for use with the Basic Cookie Auth
  LoginMethod.  Edit it to taste, and to match the cookie names you
  specified, if different than the default.

  If you're only using REMOTE_USER or Basic Auth, you
  don't need a loginForm and can delete this.  If you've developed a
  custom LoginMethod, you may need additional customization.
</dtml-comment>

<br>
<center>

<form method="post" action="<dtml-var SCRIPT_NAME><dtml-var PATH_INFO><dtml-if QUERY_STRING>?<dtml-var QUERY_STRING></dtml-if>">
<table>
 <tr><td></td><td><h1>You must login to the system</h1></td></tr>
 <tr><td></td></tr>
 <tr>
  <th align="right">Login:</th>
  <td><input type="string" name="__ac_name" size=40></td>
 </tr><tr>
  <th align="right">Password:</th>
  <td><input type="password" name="__ac_password" size=40></td>
 </tr><tr>
  <td></td>
  <td><input type="submit" name=" Log In " value=" Log In ">
 </tr>
</table>
</form>

</center>

</body></html></dtml-raise>"""

defLogoutForm = """<html><head><title>You have been logged out.</title></head>
<body bgcolor="ffffff">
 <br>
 <center>
  <H1>You have been logged out.</H1>
  <dtml-call "AUTHENTICATED_USER.logout()">
 </center>
</body></html>
"""

defForbiddenPage = """<dtml-raise "'Forbidden'"><dtml-var standard_html_header>
Sorry <dtml-var "REQUEST.AUTHENTICATED_USER">, you are forbidden to access this resource.

<dtml-comment>
  This page, if it exists, is called in the event that the user has been
  validated, but doesn't have rights to perform the requested action.

  If instead you want to have this condition cause the user to be prompted
  to log in again (normal User Folder behavior), you can delete this object.
</dtml-comment>

<dtml-comment>
<!--
  You have these roles: <dtml-var "_.string.join(REQUEST.AUTHENTICATED_USER.getRoles(), ', ')"><br>
  You need one of these roles: <dtml-var "_.string.join(needroles, ', ')"><br>
-->
</dtml-comment>

<dtml-var standard_html_footer>
</dtml-raise>"""


Generated by  Doxygen 1.6.0   Back to index