Ejemplo n.º 1
0
 def __init__(self):
     self.logger = logging.getLogger('rpx')
     self.logger.setLevel(settings.RPX_LOG_LEVEL)
     self.api = RpxApi()
Ejemplo n.º 2
0
    def authenticate(self, token=''):
        """
        TODO: pass in a message array here which can be filled with an error
        message with failure response
        """
        api = RpxApi()
        json = api.get_auth_info(token)
        if json['stat'] <> 'ok':
            return None
        profile = json['profile']
        rpx_id = profile['identifier']
        nickname = profile.get('displayName') or \
          profile.get('preferredUsername')
        email = profile.get('email', '')
        profile_pic_url = profile.get('photo')
        info_page_url = profile.get('url')
        provider=profile.get("providerName")

        user=self.get_user_by_rpx_id(rpx_id)
        
        if not user:
            # no match. we can try to match on email, though, provided that doesn't steal
            # an rpx association
            if email and profile['providerName'] in TRUSTED_PROVIDERS:
                #beware - this would allow account theft, so we only allow it
                #for trusted providers
                user_candidates=User.objects.all().filter(
                  rpxdata=None).filter(email=email)
                # if unambiguous, do it. otherwise, don't.
                if user_candidates.count()==1:
                    [user]=user_candidates
                    rpxdata=RpxData(identifier=rpx_id)
                else:
                    return None
            else:
                #no match, create a new user - but there may be duplicate user names.
                username=nickname
                user=None
                try:
                    i=0
                    while True:
                        User.objects.get(username=username)
                        username=permute_name(nickname, i)
                        i+=1
                except User.DoesNotExist:
                    #available name!
                    user=User.objects.create_user(username, email)
                rpxdata = RpxData(identifier=rpx_id)
                rpxdata.user=user
                try:
                    rpxdata.save()
                except:
                    # the object already exists
                    return False
        rpxdata = RpxData.objects.get(identifier=rpx_id)
        api.save_data(json, rpxdata, user)
        if profile_pic_url:
            rpxdata.profile_pic_url=profile_pic_url
        if info_page_url:
            rpxdata.info_page_url=info_page_url
        if provider:
            rpxdata.provider=provider
        rpxdata.save()
        return user
Ejemplo n.º 3
0
class RpxBackend:
    """Implements an authentication backend that uses RPX to authenticate users."""
    def __init__(self):
        self.logger = logging.getLogger('rpx')
        self.logger.setLevel(settings.RPX_LOG_LEVEL)
        self.api = RpxApi()
    
    def authenticate(self, token=''):
        """Required method for authentication backends."""
        auth_info = self.api.get_auth_info(token)
        
        if not auth_info:
            self.logger.error("RpxBackend: failed to get RPX info for token: " + token)
            return None
                
        return self.get_or_create_user(auth_info)   
    
    
    def get_user(self, id):    
        """Required method for authentication backends. """
        if not id:
            raise ValueError
        
        try: 
            return User.get(id) # Returns None if not found
        except db.KindError:
            self.logger.error('RpxBackend: Entity with ID ' + str(id) + ' id was not of type User!')
            return None
        except db.BadKeyError:
            self.logger.error('RpxBackend: Id ' + str(id) + ' seems malformed')
            return None
    
    
    def create_rpx_key(self, rpx_id):
        """Creates RPX Key from rpx_id.
        
        Adds "key:" prefix as suggested by
        http://code.google.com/appengine/docs/python/datastore/modelclass.html#Model
        """
        if not rpx_id:
            raise ValueError
        return dbutils.generate_key_name(rpx_id)
    
    def create_user(self, rpx_auth_info):
        """Creates user based on the RPX authentication info."""
        username = rpx_auth_info.get_user_name()

        user = dbutils.db_create(User, username=username, email=rpx_auth_info.get_email())
        if not user:
            raise Exception('Cannot create user (name = %s)' % username)
        self.logger.debug("RpxBackend: Created user(%s) as %s\r\n" % (user.username, str(user)))
        user.is_active = True
        user.is_staff = False
        user.is_superuser = False
        user.set_unusable_password()
        user.save()
        rpxdata = RpxData(key_name=self.create_rpx_key(rpx_auth_info.get_rpx_id()), user=user)
        rpxdata.save()
        self.logger.debug("RpxBackend: RpxData created\r\n")

        return user
        
    def delete_user(self, user):
        """Deletes user and any associated RPX IDs."""
        if not user or user.__class__ != User:
            raise ValueError
        
        self.logger.debug("RpxBackend: User " + user.username + " will be deleted\r\n")
        user.delete()
        # try to rely on auto_cleanup
        
        self.logger.debug("RpxBackend: User deleted\r\n")
                
    def get_user_by_rpx_id(self, rpx_id):
        """Returns user using the RPX ID."""
        if not rpx_id:
            raise ValueError
        
        rpxData = RpxData.get_by_key_name(self.create_rpx_key(rpx_id)) # Returns None if not found

        if (rpxData):
            return rpxData.user
        else:
            return None
        
    
    def map_to_existing_user_by_email(self, auth_info):
        """Map open ID to existing user based on email.
        
        The open Id provider needs to be in the TRUSTED_PROVIDERS
        list to be able to do this mapping.
        """
        if not auth_info or auth_info.__class__ != RpxAuthInfo:
            raise ValueError
        
        user = None
        
        if auth_info.get_provider() in TRUSTED_PROVIDERS:
            
            user_candidates = dbutils.get_object_list(User, 'email = ', auth_info.get_email())
  
            if user_candidates.count() == 1:
                users = user_candidates.fetch(1)
                user = users[0]
                rpxdata = RpxData(key_name=self.create_rpx_key(auth_info.get_rpx_id()), user=user)
                self.logger.info("RpxBackend: New RPX id for existing user: "******"""Returns existing user or create new user.
        
        Based on the information in auth_info, this func either retuns an existing user,
        mapps a new open ID to an existing user and returns that user, or creates and
        returns a new user.
        """
        if not auth_info or auth_info.__class__ <> RpxAuthInfo:
            raise ValueError
        
        # Try to get user from RPX ID
        user = self.get_user_by_rpx_id(auth_info.get_rpx_id())

        # Map to existing user email if trusted provider
        if not user:
            user = self.map_to_existing_user_by_email(auth_info)

        # New user, create
        if not user:
            user = self.create_user(auth_info)
        
        return user
    
    def map_id_to_existing_user(self, token, user):
        """Map existing user to new open ID.

        This function should be used to add new open IDs to users that already
        are authenticated.
        
        """
        if not token and not user:
            raise ValueError
        
        auth_info = api.get_auth_info(token)
        
        if auth_info.get_status() == RpxAuthInfo.OK:
            
            # Make sure that this id isn't used
            existing_user = self.get_user_by_rpx_id(auth_info.get_rpx_id())
            
            if not existing_user:
                rpxdata = RpxData(key_name=self.create_rpx_key(auth_info.get_rpx_id()), user=user)
                rpxdata.save()