On 7/26/06, [EMAIL PROTECTED] <[EMAIL PROTECTED]> wrote:

Hello.
We have a Jira issue tracking system that exposes user, group, and
permission attributes through a SOAP interface. Is replacing the
internal TG identity model to use this faciltiy viable?
I haven't looked closely yet, but most examples (for SMB and Ldap) farm
off only the password lookup but manage all the other attributes within
turbogears. I have this much working and I am wondering I  could ( or
more importantly 'should') try to interface with the group and
permissions data on the Jira server.

You can replace the provider fully without any problems.

both the SMB and ldap are a hack on top of the SQLObjectProvider. I was working on an update to make a default provider class and make all providers extend that but I stop due to the SQLAlchemy layer being redo and my time limits.

Any comments or suggetions are welcome.

attach is my half working "provider bases class", is very well documented, and it has everything that is common to all providers and should stay the same so you wont break anything. Although you should strip out the parts of creating/managing the model since I think that will be handle by the external Jira server.

the only part that is still in the dark is the setGlobal function which I haven't got to work. but the current code doesn't uses it so you could just strip it.

by the way this is just on my TG CO and it was made with an older revision, from pre 0.9a6 I believe, I just did an svn up and the conflicts don't seem to affect it.

if your wondering when I'll finish this I honestly don't know. I may try to get some time on this weekend but I'm working on another personal project.

I hope my code helps you and if you have any question please just ask.
Nicky



--~--~---------~--~----~------------~-------~--~----~
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
    


__ALL__ = ["SqlIdentityProvider","setGlobal","SqlIdentity"]

Reply via email to