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"]
- [TurboGears] Re: RFC: Using Identity with external source for... Jorge Vargas

