def update_user_state(self, user, state): if user not in self.fhs.keys(): raise totpcgi.UserStateError("%s's state FH has gone away!" % user) import json fh = self.fhs[user] logger.debug('fh.name=%s' % fh.name) js = { 'fail_timestamps' : state.fail_timestamps, 'success_timestamps' : state.success_timestamps, 'used_scratch_tokens' : state.used_scratch_tokens } logger.debug('saving state=%s' % js) logger.debug('Saving new state for user %s' % user) json.dump(js, fh, indent=4) fh.truncate() logger.debug('Unlocking state file for user %s' % user) flock(fh, LOCK_UN) fh.close() del self.fhs[user] logger.debug('fhs=%s' % self.fhs)
def update_user_state(self, user, state): logger.debug('Writing new state for user %s', user) if user not in self.locks.keys(): raise totpcgi.UserStateError("%s's MySQL lock has gone away!" % user) userid = self.locks[user] cur = self.conn.cursor() cur.execute('DELETE FROM timestamps WHERE userid=%s', (userid, )) cur.execute('DELETE FROM used_scratch_tokens WHERE userid=%s', (userid, )) for timestamp in state.fail_timestamps: cur.execute( ''' INSERT INTO timestamps (userid, success, timestamp) VALUES (%s, %s, %s)''', (userid, False, timestamp)) for timestamp in state.success_timestamps: cur.execute( ''' INSERT INTO timestamps (userid, success, timestamp) VALUES (%s, %s, %s)''', (userid, True, timestamp)) for token in state.used_scratch_tokens: cur.execute( ''' INSERT INTO used_scratch_tokens (userid, token) VALUES (%s, %s)''', (userid, token)) if state.counter >= 0 and self.has_counters: cur.execute('DELETE FROM counters WHERE userid=%s', (userid, )) cur.execute( ''' INSERT INTO counters (userid, counter) VALUES (%s, %s)''', (userid, state.counter)) logger.debug('Releasing lock for userid=%s', userid) cur.execute('SELECT RELEASE_LOCK(%s)', (userid, )) self.conn.commit() del self.locks[user]
def get_user_state(self, user): state = totpcgi.GAUserState() import json # load the state file and keep it locked while we do verification state_file = os.path.join(self.state_dir, user) + '.json' logger.debug('Loading user state from: %s' % state_file) # For totpcgiprov and totpcgi to be able to write to the same state # file, we have to create it world-writable. Since we have restricted # permissions on the parent directory (totpcgi:totpcgiprov), plus # selinux labels in place, this should keep this safe from tampering. os.umask(0000) # we exclusive-lock the file to prevent race conditions resulting # in potential token reuse. if os.access(state_file, os.W_OK): logger.debug('%s exists, opening r+' % state_file) fh = open(state_file, 'r+') logger.debug('Locking state file for user %s' % user) lockf(fh, LOCK_EX) try: js = json.load(fh) logger.debug('loaded state=%s' % js) state.fail_timestamps = js['fail_timestamps'] state.success_timestamps = js['success_timestamps'] state.used_scratch_tokens = js['used_scratch_tokens'] if 'counter' in js: state.counter = js['counter'] except Exception, ex: # We fail out of caution, though if someone wanted to # screw things up, they could have done so without making # the file un-parseable by json -- all they need to do is to # erase the file. logger.debug('Parsing json failed with: %s' % ex) logger.debug('Unlocking state file for user %s' % user) lockf(fh, LOCK_UN) raise totpcgi.UserStateError( 'Error parsing the state file for: %s' % user) fh.seek(0)
def get_user_state(self, user): state = totpcgi.GAUserState() import json # load the state file and keep it locked while we do verification state_file = os.path.join(self.state_dir, user) + '.json' logger.debug('Loading user state from: %s' % state_file) # Don't let anyone but ourselves see the contents of the state file os.umask(0077) # we exclusive-lock the file to prevent race conditions resulting # in potential token reuse. if os.access(state_file, os.R_OK): logger.debug('%s exists, opening r+' % state_file) fh = open(state_file, 'r+') logger.debug('Locking state file for user %s' % user) flock(fh, LOCK_EX) try: js = json.load(fh) logger.debug('loaded state=%s' % js) state.fail_timestamps = js['fail_timestamps'] state.success_timestamps = js['success_timestamps'] state.used_scratch_tokens = js['used_scratch_tokens'] except Exception, ex: # We fail out of caution, though if someone wanted to # screw things up, they could have done so without making # the file un-parseable by json -- all they need to do is to # erase the file. logger.debug('Parsing json failed with: %s' % ex) logger.debug('Unlocking state file for user %s' % user) flock(fh, LOCK_UN) raise totpcgi.UserStateError( 'Error parsing the state file for: %s' % user) fh.seek(0)
def update_user_state(self, user, state): logger.debug('Writing new state for user %s' % user) if user not in self.locks.keys(): raise totpcgi.UserStateError("%s's pg lock has gone away!" % user) userid = self.locks[user] cur = self.conn.cursor() cur.execute('DELETE FROM timestamps WHERE userid=%s', (userid, )) cur.execute('DELETE FROM used_scratch_tokens WHERE userid=%s', (userid, )) for timestamp in state.fail_timestamps: cur.execute( ''' INSERT INTO timestamps (userid, success, timestamp) VALUES (%s, %s, %s)''', (userid, False, timestamp)) for timestamp in state.success_timestamps: cur.execute( ''' INSERT INTO timestamps (userid, success, timestamp) VALUES (%s, %s, %s)''', (userid, True, timestamp)) for token in state.used_scratch_tokens: cur.execute( ''' INSERT INTO used_scratch_tokens (userid, token) VALUES (%s, %s)''', (userid, token)) logger.debug('Unlocking advisory lock for userid=%s' % userid) cur.execute('SELECT pg_advisory_unlock(%s)', (userid, )) self.conn.commit() del self.locks[user]
# screw things up, they could have done so without making # the file un-parseable by json -- all they need to do is to # erase the file. logger.debug('Parsing json failed with: %s' % ex) logger.debug('Unlocking state file for user %s' % user) flock(fh, LOCK_UN) raise totpcgi.UserStateError( 'Error parsing the state file for: %s' % user) fh.seek(0) else: logger.debug('%s does not exist, opening w' % state_file) try: fh = open(state_file, 'w') except IOError: raise totpcgi.UserStateError( 'Cannot write user state for %s, exiting.' % user) logger.debug('Locking state file for user %s' % user) flock(fh, LOCK_EX) # The following condition should never happen, in theory, # because we have an exclusive lock on that file. If it does, # things have broken somewhere (probably locking is broken). if user not in self.fhs.keys(): self.fhs[user] = fh return state def update_user_state(self, user, state): if user not in self.fhs.keys(): raise totpcgi.UserStateError("%s's state FH has gone away!" % user)