예제 #1
0
 def test_get_and_set_DatabasePasswordByUser_simple(self):
     from django.conf import settings
     from psafefe.psafe.models import *
     from psafefe.psafe.functions import getUsersPersonalSafe, getDatabasePasswordByUser, setDatabasePasswordByUser
     # Create a user with read/write access to the test safe repo
     username, user = self.getUser(
                                   userClass = 'user',
                                   groups = [
                                             self.groupsByRepo['testsafes']['writes'],
                                             self.groupsByRepo['testsafes']['reads'],
                                             ],
                                   )
     userpass = self.getUserPass(user = user)
     
     mySafe = getUsersPersonalSafe(
                                   user = user,
                                   userPassword = userpass,
                                   wait = True,
                                   )
     self.assertTrue(mySafe)
     
     # Get the DB we're working with
     db = PasswordSafe.objects.get(
                                   repo = self.groupsByRepo['testsafes']['repo'],
                                   filename__endswith = "simple.psafe3",
                                   )
     
     # Save the DB password
     setDatabasePasswordByUser(
                               user = user,
                               userPassword = userpass,
                               psafe = db,
                               psafePassword = '******',
                               wait = True,
                               )
     
     # Try with ppsafe set 
     dbPassword = getDatabasePasswordByUser(
                                            user = user,
                                            userPassword = userpass,
                                            psafe = db,
                                            ppsafe = mySafe,
                                            wait = True,
                                            )  
     self.assertEqual(dbPassword, 'bogus12345', "Password for simple.psafe3 is wrong or has changed. Was trying without passing in a personal psafe to getDatabasePasswordByUser")      
     # try without ppsafe set
     dbPassword = getDatabasePasswordByUser(
                                            user = user,
                                            userPassword = userpass,
                                            psafe = db,
                                            ppsafe = None,
                                            wait = True,
                                            )
     self.assertEqual(dbPassword, 'bogus12345', "Password for simple.psafe3 is wrong or has changed. Was trying with passing in a personal psafe to getDatabasePasswordByUser")
예제 #2
0
    def getCached(self, canLoad=False, user=None, userPassword=None):
        """ Return the RAM only cached data for this safe. 
        @param canLoad: Indicates what to do if the entry doesn't exist. False: Error out. True: Load the safe then return the obj.  
        """
        self.log.debug("Getting cached copy")
        from psafefe.psafe.errors import EntryNotCached

        # Can't load without the password
        from django.contrib.auth.models import User

        if not isinstance(user, User):
            canLoad = False
            self.log.debug("Can't load due to lack of valid user (%r)" % user)
        if not userPassword:
            canLoad = False
            self.log.debug("Can't load due to lack of valid password for user (%r)" % userPassword)
        try:
            return self.mempsafe
        except MemPSafe.DoesNotExist, e:
            if canLoad:
                self.log.debug("Going to try loading")
                try:
                    from psafefe.psafe.tasks.load import loadSafe
                    from psafefe.psafe.functions import getDatabasePasswordByUser

                    dbPassword = getDatabasePasswordByUser(user=user, userPassword=userPassword, psafe=self, wait=True)
                    ls = loadSafe.delay(psafe_pk=self.pk, password=dbPassword, force=False)  # @UndefinedVariable
                    ls.wait()
                    # Make sure to prevent inf. recursion if the load fails
                    return self.getCached(canLoad=False)
                except Exception, e:
                    raise EntryNotCached, "%r doesn't have a cached entry and loading failed with %r" % (self, e)
예제 #3
0
def updatePSafeCacheByPSafesPK(username, password, entPKsUnsafe, sync, **kw):
    """ Update the psafe cache for the given entities. If sync is true, 
    then wait for the cache to update before returning. 
    @note: Any safes that the user doesn't have a valid password for will be skipped.
    @note: Any PKs to which a safe doesn't exist or the user lacks at least read-only perms will raise an EntryDoesntExistError.
    
    @warning: If sync is not set the count of successes will NOT include any errors that occur during sync. It will only include ones where the safe password lookup and object lookup succeeded.     
    @param username: Requesting user's login
    @type username: string
    @param password: Requesting user's login
    @type password: string
    @param entPKs: A list of safe PKs that should have their cache updated.
    @type entPKs: list of ints
    @param sync: If True, wait for the safes to be updated before returning. 
    @type sync: boolean
    @return: If sync=False, the number of safes that have had a sync job successfully submitted. If sync=True, then the number of safes that had a sync job submitted andsuccessfullyy completed.  
    @raise NoPermissionError: User doesn't have password safe sync permissions
    """
    # Validate all safes and the users perms to them first
    ents = []
    for pk in list(entPKsUnsafe):
        try:
            ent = PasswordSafe.objects.get(pk = pk)
            ents.append(ent)
        except PasswordSafe.DoesNotExist:
            raise EntryDoesntExistError, "Couldn't find a PasswordSafe where pk=%r" % pk
        if not ent.repo.user_can_access(user = kw['user'], mode = "R"):
            raise EntryDoesntExistError, "Couldn't find a PasswordSafe where pk=%r" % pk
    sync = bool(sync)
    
    if kw['user'].has_perm('psafe.can_sync_passwordsafe'):
        # user has perms
        waits = []
        successes = 0
        for psafe in ents:
            try:
                psafepass = getDatabasePasswordByUser(kw['user'], password, psafe)
                waits.append(loadSafe.delay(psafe_pk = entPK, password = psafepass))  # @UndefinedVariable
                successes += 1
            except:
                # TODO: Add some sort of logging for this
                pass
        # Doing sync, wait for all results
        if sync:
            for i in waits:
                try:
                    i.wait()
                except:
                    # TODO: Add some sort of logging for this
                    successes -= 1
        return successes
    raise NoPermissionError, "User can't sync psafes"
예제 #4
0
def updatePSafeCacheByPSafesByUUID(username, password, entUUIDsUnsafe, sync, **kw):
    """ Update the psafe cache for the given entities. If sync is true, 
    then wait for the cache to update before returning. 
    @note: Any safes that the user doesn't have a valid password for will be skipped. 
    @note: If the user lacks perms to any psafe an EntryDoesntExistError will be raised
    @note: If one of the UUIDs doesn't exist, then an EntryDoesntExistError will be raised.
    @note: If the user has perms to multiple psafes with the same UUID and that UUID is listed, a MultipleEntriesExistError will be raised
    @warning: If sync is not set the count of successes will NOT include any errors that occur during sync. It will only include ones where the safe password lookup and object lookup succeeded.     
    @param username: Requesting user's login
    @type username: string
    @param password: Requesting user's login
    @type password: string
    @param entUUIDs: A list of safe UUIDs that should have their cache updated.
    @type entUUIDs: list of strings
    @param sync: If True, wait for the safes to be updated before returning. 
    @type sync: boolean
    @return: The number of safes successfully updated
    @raise NoPermissionError: User doesn't have password safe sync permissions
    @raise EntryDoesntExistError: No psafe with the request UUID exists that the user as atleast read-only access to. 
    @raise MultipleEntriesExistError: More than one psafe with the given UUID was found. 
    """    
    # Validate input type    
    entUUIDs = []
    for pk in list(entUUIDsUnsafe):
        entUUIDs.append(str(pk))
    sync = bool(sync)

    if kw['user'].has_perm('psafe.can_sync_passwordsafe'):
        # user has perms
        # Validate all safes BEFORE we start calling loadSafe
        validSafes = []
        for entUUID in entUUIDs:
            psafes = PasswordSafe.objects.filter(uuid = entUUID)
            # Validate perms
            okPSafes = []
            for ent in psafes:
                if ent.repo.user_can_access(user = kw['user'], mode = "R"):
                    okPSafes.append(ent) 
            # Only allow one UUID
            if len(psafes) > 1:
                raise MultipleEntriesExistError, "%r safes with a UUID of %r were found" % (psafes.count(), entUUID)
            elif len(psafes) == 0:
                raise EntryDoesntExistError, "Couldn't find a PasswordSafe where uuid=%r" % entUUID
            validSafes.append(psafes[0])
        # All safes found are valid, so start the loadSafes
        waits = []
        successes = 0
        for psafe in validSafes:
            try:
                psafepass = getDatabasePasswordByUser(kw['user'], password, psafe)
                waits.append(loadSafe.delay(psafe_pk = entPK, password = psafepass))  # @UndefinedVariable
                successes += 1
            except:
                # TODO: Add some sort of logging for this
                pass
        # Doing sync, wait for all results and watch for errors
        if sync:
            for i in waits:
                try:
                    i.wait()
                except:
                    # TODO: Add some sort of logging for this
                    successes -= 1
        return successes
    else:
        raise NoPermissionError, "User can't sync psafes"
예제 #5
0
    try:
        safe = PasswordSafe.objects.get(pk=safeID)
    except PasswordSafe.DoesNotExist, e:
        log.warning("Got %r while trying to fetch Password Safe %r", e, safeID)
        raise EntryDoesntExistError("No safe with an ID of %r" % safeID)

    # Convert possible string into a list
    if isinstance(deviceID, list):
        log.debug("DeviceID is already a list, doing nothing to %r", deviceID)
    elif isinstance(deviceID, str):
        deviceID = deviceID.split('.')
        log.debug("DeviceID is a string, split into %r", deviceID)
    else:
        raise ValueError("Expected deviceID to be a string or a list, not %r" % deviceID)

    psafePassword = getDatabasePasswordByUser(kw['user'], password, safe, wait=True)

    actions = []

    if 'shellLogins' in info:
        for shellUser, shellPassword in info['shellLogins'].items():
            actions.append({
                            'action':'add-update',
                            'refilters':{},
                            'vfilters':{
                                        'Group':deviceID,
                                        'Username':shellUser,
                                        'Title':"Logins",
                                        },
                            'changes':{
                                       'Password':shellPassword,
예제 #6
0
def _filterComplex(username, password, safeIDs, include, exclude, **kw):
    """ 
    @param username: Requesting user's login
    @type username: string
    @param password: Requesting user's login
    @type password: string
    @param safeIDs: The PKs of all psafe objects that should be included in the search. 
    @type safeIDs: A list of ints
    @param include: A dict indicating what fields must match and possible values to match against.  
    @type include: A dict where keys are the fields names and the values are a list of possible values for matching entries.
    @param exclude: A dict indicating what fields/values must NOT match.   
    @type exclude: A dict where keys are the fields names and the values are a list of possible values for entries that should be excluded.
    @return: A list of dicts containing all matching entries
    @raise EntryDoesntExistError: The requested entry doesn't exist or the user doesn't have permission to read it.
    @raise InvalidQueryError: One or more of the include/exclude field names or list of values is not valid.
    @note: Valid fields for filters: PK, UUID, Group, Title, Username, Notes, Password, Creation Time, Password Last Modification Time, Last Access Time, Password Expiry, Entry Last Modification Time, URL, AutoType, Run Command, Email.
    
    @warning: WHEN UPDATING THE ARG LIST OR THIS DOC STRING, MAKE SURE TO UPDATE THE RPC FUNCTIONS BELOW!  
    """
    extra = dict(username = username, safeIDs = safeIDs, user = kw['user'],)
    for safeID in safeIDs:
        if not isinstance(safeID, int):
            log.warn("The safeID/pk %r is not an int", safeID, extra = extra)
            raise InvalidQueryError("The safeID/pk %r is not an int" % safeID)

    if len(safeIDs) == 1:
        extra['safePK'] = safeID

    if not isinstance(safeIDs, list):
        log.warn("The list of safeIDs/safePKs is not a list. Got type %r, value %r. ", type(safeIDs), safeIDs, extra = extra)
        raise InvalidQueryError("The list of safeIDs/safePKs is not a list. Got %r." % type(safeIDs))

    safes = PasswordSafe.objects.filter(pk__in = safeIDs).select_related()

    # Let the user know which safeIDs couldn't be found.
    if len(safes) != len(safeIDs):
        log.warning("The list of PasswordSafe objects returned (%d) is a different length than the list of safeIDs (%d). ", len(safes), len(safeIDs), extra = extra)
        for safeID in safeIDs:
            if safes.filter(pk = safeID).count() == 0:
                raise EntryDoesntExistError("No safe with an ID of %r" % safeID)

    # Validate the user's access to all of the safes
    for safe in safes:
        if safe.repo.user_can_access(user = kw['user'], mode = "R"):
            log.debug("User %r is ok to access %r", kw['user'], safe.repo, extra = extra)
        else:
            log.warning("User %r is NOT allowed to access %r", kw['user'], safe.repo, extra = extra)
            # raise NoPermissionError("User %r can't access this repo" % kw['user'])
            raise EntryDoesntExistError("No safe with an ID of %r" % safeID)
        safes.append(safe)
    extra['safes'] = safes

    log.debug("User %r is querying %d safes", kw['user'], len(safes), extra = extra)

    # Get the cached entry or load it if needed
    memSafes = {}
    for safe in safes:
        psafePassword = getDatabasePasswordByUser(kw['user'], password, safe, wait = True)
        memSafes[safe.pk] = safe.getCached(canLoad = True, user = kw['user'], userPassword = password)

    extra['memSafes'] = memSafes
    if len(memSafes) == 1:
        extra['memSafePK'] = memSafes.keys()[0]

    # Provide basic validation of the filters since the DB filter errors aren't passed on to the user
    for filterName, filterDict in [ ('include', include), ('exclude', exclude), ]:
        for field, values in filterDict.items():
            if field not in FILTER_FIELDS_MAPPING:
                log.warning("User %r passed in field %r which isn't valid", kw['user'], field, extra = extra)
                raise InvalidQueryError("The field %r:%r in %r is not a valid field name" % (field, values, filterName))
            if not isinstance(values, list):
                log.warning("User %r passed in a value of %r for field %r. The value needs to be a list. ", kw['user'], values, field, extra = extra)
                raise InvalidQueryError("The value list for field %r, which is %r, is not a list" % (field, values))
            fieldType, modelFieldName = FILTER_FIELDS_MAPPING[field]
            for value in values:
                if not isinstance(value, fieldType):
                    log.warning("User %r passed in value %r for field %r which isn't %r", kw['user'], value, fieldType, extra = extra)
                    raise InvalidQueryError("The value %r from field %r in filter %r is not of type %r" % (value, field, filterName, fieldType))

    # Passed sanity checks of data...now to build the query
    entryFilter = MemPsafeEntry.objects.filter(safe__in = memSafes.values())
    try:
        for field, values in include.items():
            if field == 'Old Passwords':
                for value in values:
                    entryFilter = entryFilter.filter(mempasswordentryhistory__contains = value)
            else:
                fieldFilterName = "%s__in" % field
                entryFilter = entryFilter.filter(**{fieldFilterName:values})
    except Exception, e:
        log.warn("Error processing include filter: %r User: %r", e, kw['user'], exc_info = sys.exc_info(), extra = extra)
        raise InvalidQueryError("Error in include filter")