On 6/12/06, Charles Duffy <[EMAIL PROTECTED]> wrote:

Howdy. I'm interested in using HTTP authentication rather than a
forms-based approach for a portion of my site intended to be accessed
programmatically. Is there a sane way to do this?

yes create a new identity provider.

I'm thinking I may need to make my own decorator for the purpose, but
it'd be nice if that weren't so. On the other hand, is there a
reasonably simple approach by which I could add such functionality to
TurboGears proper (say, as a parameter for the existing
Identity-related decorators) rather than doing it as a once-off for my
own project?

right now i'm working on a reorganization of the module that will make this easier. but basically what you need is to provide an interface similar to what the soprovider.py does.

My code is almost done I need only a flew final adjustments. and I need to redo the sqlalchemy part but that doesn't concerns you.

I have attach what will be the generic identity provider module. please notice this isn't ready but will give you an idea of what is the mininum the module should implement. from then on you should decide if tg identity is too much for what you need or not.







--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "TurboGears" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/turbogears
-~----------~----~----~----~------~----~------~--~---

import sha
import md5
import random
from turbojson.jsonify import *
from datetime import *

import logging

log = logging.getLogger("turbogears.identity.provider")

import turbogears

from turbogears import identity

try:
    set, frozenset
except NameError:
    from sets import Set as set, ImmutableSet as frozenset

def to_db_encoding(s, encoding):
    if isinstance(s, str):
        pass
    elif hasattr(s, '__unicode__'):
        s = unicode(s)
    if isinstance(s, unicode):
        s = s.encode(encoding)
    return s

log.debug(currentProvider)

[EMAIL PROTECTED] reference to identity.current_provider is some way.
#and change all reference of SqlIdentity to current_provider

# Global class references -- these will be set when the Provider is initialised.
user_class= None
group_class= None
permission_class= None
visit_class= None

class SqlIdentity(object):
    def __init__(self, visit_key, user=None):
        if user:
            self._user= user
        self.visit_key= visit_key
    
    def _get_user(self):
        try:
            return self._user
        except AttributeError:
            # User hasn't already been set
            pass
        # Attempt to load the user. After this code executes, there *WILL* be
        # a _user attribute, even if the value is None.
        try:
            visit= visit_class.by_visit_key( self.visit_key )
        [EMAIL PROTECTED] unify this into one check    
        except SQLObjectNotFound:
        #if not visit: <-- sqlalchemy way
            # The visit ID is invalid
            self._user= None
            return None
        self._user= user_class.get( visit.user_id )
        return self._user
    user= property(_get_user)
    
    def _get_user_name(self):
        if not self.user:
            return None
        return self.user.user_name
    user_name= property(_get_user_name)

    def _get_anonymous(self):
        return not self.user
    anonymous= property(_get_anonymous)
    
    def _get_permissions(self):
        try:
            return self._permissions
        except AttributeError:
            # Permissions haven't been computed yet
            pass
        if not self.user:
            self._permissions= frozenset()
        else:
            self._permissions= frozenset([p.permission_name for p in self.user.permissions])
        return self._permissions
    permissions= property(_get_permissions)
    
    def _get_groups(self):
        try:
            return self._groups
        except AttributeError:
            # Groups haven't been computed yet
            pass
        if not self.user:
            self._groups= frozenset()
        else:
            self._groups= frozenset([g.group_name for g in self.user.groups])
        return self._groups
    groups= property(_get_groups)
    def logout(self):
        '''
        Remove the link between this identity and the visit.
        '''
        if not self.visit_key:
            return
        try:
            [EMAIL PROTECTED]
            #visit= get visit key
            #delete visit object/derefence
            # Clear the current identity
            #maybe pass in the method name to run here to __init__
            anon= SqlIdentity(None,None)
            anon.anonymous= True
            identity.set_current_identity( anon )
        except:
            pass


[EMAIL PROTECTED] test
#this method/function will help a lot in cleaning up SqlIdentityProvider subclasses.
#this method will be use to load the (user,group,permission)_class, object although it could be very good for "extensions"
# like the smb_domain in http://trac.turbogears.org/turbogears/attachment/wiki/IdentityManagement/sosmbprovider.2.py
def setGlobal(_class,key,default):
    global _class
    _class_path= turbogears.config.get( key,__name__ + "." + default)
    _class= load_class(user_class_path)
    if _class:
        log.info("Succesfully loaded \"%s\"" % _class_path)
    
class SqlIdentityProvider(object):
    '''
    IdentityProvider that uses a model from a database (via SQLObject).
    '''
    [EMAIL PROTECTED] update this to work with setGlobal
    def __init__(self):
        get=turbogears.config.get
        
        global user_class, group_class, permission_class, visit_class
        user_class_path= get( "identity.soprovider.model.user", __name__ + ".TG_User" )

        user_class= load_class(user_class_path)
        if user_class:
            log.info("Succesfully loaded \"%s\"" % user_class_path)
            #~ encoding?
        group_class= load_class(group_class_path)
        if group_class:
            log.info("Succesfully loaded \"%s\"" % group_class_path)

        permission_class= load_class(permission_class_path)
        permission_class_path= get( "identity.soprovider.model.permission",__name__ + ".TG_Permission" )
        if permission_class:
            log.info("Succesfully loaded \"%s\"" % permission_class_path)
        visit_class_path= get( "visit.soprovider.model",__name__ + ".TG_VisitIdentity" )
        visit_class= load_class(visit_class_path)
        if visit_class:
            log.info("Succesfully loaded \"%s\"" % visit_class_path)
        
            
        # Default encryption algorithm is to use plain text passwords
        [EMAIL PROTECTED] factor this out into a function that can be read from the project to add support for stuff like 
        # having autorization from /etc/shadow or like does smbsoprovider.py or plaintext j/k 
        # the idea is that the value of the encrpytion_algoritm will change from a str to a callable
        algorithm= get( "identity.soprovider.encryption_algorithm", None )
        if "md5"==algorithm:
            self.encrypt_password= lambda pw: md5.new(pw).hexdigest()
        elif "sha1"==algorithm:
            self.encrypt_password= lambda pw: sha.new(pw).hexdigest()
        else:
            self.encrypt_password= lambda pw: pw

    def create_provider_model( self ):
        # create the database tables
        pass
        
    def validate_identity( self, user_name, password, visit_key ):
        '''
        Look up the identity represented by user_name and determine whether the
        password is correct.
        
        Must return either None if the credentials weren't valid or an object
        with the following properties:
            user_name: original user name
            user: a provider dependant object (TG_User or similar)
            groups: a set of group IDs
            permissions: a set of permission IDs
        '''
        pass

    def validate_password(self, user, user_name, password):
        '''
        Check the supplied user_name and password against existing credentials.
        Note: user_name is not used here, but is required by external
        password validation schemes that might override this method.
        If you use SqlObjectIdentityProvider, but want to check the passwords
        against an external source (i.e. PAM, a password file, Windows domain),
        subclass SqlObjectIdentityProvider, and override this method.
        '''
        pass

    def load_identity( self, visit_key ):
        '''
        Lookup the principal represented by user_name. Return None if there is no
        principal for the given user ID.
        
        Must return an object with the following properties:
            user_name: original user name
            user: a provider dependant object (TG_User or similar)
            groups: a set of group IDs
            permissions: a set of permission IDs
        '''
        return SqlIdentity( visit_key )
    
    def anonymous_identity( self ):
        '''
        Must return an object with the following properties:
            user_name: original user name
            user: a provider dependant object (TG_User or similar)
            groups: a set of group IDs
            permissions: a set of permission IDs
        '''
        return SqlIdentity( visit_key ) 

 
[EMAIL PROTECTED] add comments on what is the basic default model, for people implementing subclasses 
class TG_VisitIdentity(object):
    pass
    
class TG_Group(object):
    pass

class TG_User(object):
    pass
    
class TG_Permission(object):
    pass
    

Reply via email to