def test_valid_password(self): dummy_password = "******" hashed_once = hash_password(dummy_password, dummy_salt) hashed_twice = hash_password(dummy_password, dummy_salt) self.assertTrue(hashed_once, hashed_twice) self.assertTrue(check_password(dummy_password, dummy_salt, hashed_once))
def db_admin_update_user(session, state, tid, user_id, request, language): """ Updates the specified user. """ fill_localized_keys(request, models.User.localized_keys, language) user = db_get_user(session, tid, user_id) if user.username != request['username']: check = session.query(models.User).filter( models.User.username == text_type(request['username']), models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid).one_or_none() if check is not None: raise errors.InputValidationError('Username already in use') user.update(request) password = request['password'] if password: user.password = security.hash_password(password, user.salt) user.password_change_date = datetime_now() # The various options related in manage PGP keys are used here. parse_pgp_options(state, user, request) if user.role == 'admin': db_refresh_memory_variables(session, [tid]) return user
def db_user_update_user(session, state, tid, user_id, request): """ Updates the specified user. This version of the function is specific for users that with comparison with admins can change only few things: - real name - email address - preferred language - the password (with old password check) - pgp key raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist. """ from globaleaks.handlers.admin.notification import db_get_notification from globaleaks.handlers.admin.node import db_admin_serialize_node user = models.db_get(session, models.User, models.User.id == user_id) user.language = request.get('language', State.tenant_cache[tid].default_language) user.name = request['name'] new_password = request['password'] old_password = request['old_password'] if new_password: if user.password_change_needed: user.password_change_needed = False else: if not check_password(old_password, user.salt, user.password): raise errors.InvalidOldPassword user.password = hash_password(new_password, user.salt) user.password_change_date = datetime_now() # If the email address changed, send a validation email if request['mail_address'] != user.mail_address: user.change_email_address = request['mail_address'] user.change_email_date = datetime_now() user.change_email_token = generateRandomKey(32) user_desc = user_serialize_user(session, user, user.language) template_vars = { 'type': 'email_validation', 'user': user_desc, 'new_email_address': request['mail_address'], 'validation_token': user.change_email_token, 'node': db_admin_serialize_node(session, 1, user.language), 'notification': db_get_notification(session, tid, user.language) } state.format_and_send_mail(session, tid, user_desc, template_vars) # If the platform allows users to change PGP keys, process it if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True: parse_pgp_options(state, user, request) return user
def db_get_wbtip_by_receipt(session, tid, receipt): hashed_receipt = security.hash_password(receipt, State.tenant_cache[tid].receipt_salt) return session.query(InternalTip) \ .filter(WhistleblowerTip.receipt_hash == text_type(hashed_receipt, 'utf-8'), WhistleblowerTip.tid == tid, InternalTip.id == WhistleblowerTip.id, InternalTip.tid == WhistleblowerTip.tid).one_or_none()
def login_whistleblower(session, tid, receipt, client_using_tor): """ login_whistleblower returns a session """ hashed_receipt = security.hash_password( receipt, State.tenant_cache[tid].receipt_salt) result = session.query(WhistleblowerTip, InternalTip) \ .filter(WhistleblowerTip.receipt_hash == text_type(hashed_receipt, 'utf-8'), WhistleblowerTip.tid == tid, InternalTip.id == WhistleblowerTip.id, InternalTip.tid == WhistleblowerTip.tid).first() if result is None: log.debug("Whistleblower login: Invalid receipt") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication wbtip, itip = result[0], result[1] if not client_using_tor and not State.tenant_cache[tid][ 'https_whistleblower']: log.err("Denied login request over clear Web for role 'whistleblower'") raise errors.TorNetworkRequired itip.wb_last_access = datetime_now() return new_session(tid, wbtip.id, 'whistleblower', False)
def db_create_user(session, state, tid, request, language): request['tid'] = tid fill_localized_keys(request, models.User.localized_keys, language) if request['username']: user = session.query(models.User).filter( models.User.username == text_type(request['username']), models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid).one_or_none() if user is not None: raise errors.InputValidationError('Username already in use') user = models.User({ 'tid': tid, 'username': request['username'], 'role': request['role'], 'state': u'enabled', 'name': request['name'], 'description': request['description'], 'language': language, 'password_change_needed': request['password_change_needed'], 'mail_address': request['mail_address'], 'can_edit_general_settings': request['can_edit_general_settings'] }) if not request['username']: user.username = user.id = uuid4() if request['password']: password = request['password'] else: password = u'password' user.salt = security.generateRandomSalt() user.password = security.hash_password(password, user.salt) # The various options related in manage PGP keys are used here. parse_pgp_options(state, user, request) session.add(user) session.flush() db_create_usertenant_association(session, user.id, tid) return user
def db_create_user(session, state, tid, request, language): request['tid'] = tid fill_localized_keys(request, models.User.localized_keys, language) if request['username']: user = session.query(models.User).filter( models.User.tid == tid, models.User.username == text_type( request['username'])).one_or_none() if user is not None: raise errors.InputValidationError('Username already in use') user = models.User({ 'tid': tid, 'username': request['username'], 'role': request['role'], 'state': u'enabled', 'name': request['name'], 'description': request['description'], 'name': request['name'], 'language': language, 'password_change_needed': request['password_change_needed'], 'mail_address': request['mail_address'] }) if request['password']: password = request['password'] elif user.role == 'receiver': # code necessary because the user.role for recipient is receiver password = '******' else: password = user.role user.salt = security.generateRandomSalt() user.password = security.hash_password(password, user.salt) # The various options related in manage PGP keys are used here. parse_pgp_options(state, user, request) session.add(user) session.flush() if not request['username']: user.username = user.id return user
def test_pass_hash(self): dummy_password = "******" dummy_salt = generateRandomSalt() sure_bin = scrypt.hash(dummy_password, dummy_salt) sure = binascii.b2a_hex(sure_bin) not_sure = hash_password(dummy_password, dummy_salt) self.assertEqual(sure, not_sure)
def test_check_password(self): password = '******' password_hash = hash_password(password, dummy_salt) self.assertFalse(check_password('x', dummy_salt, password_hash)) self.assertFalse(check_password(password, 'x', password_hash)) self.assertFalse(check_password(password, dummy_salt, 'x')) self.assertTrue(check_password(password, dummy_salt, password_hash))
def get_internalfiles_by_receipt(self, session, receipt): hashed_receipt = security.hash_password( receipt, State.tenant_cache[1].receipt_salt) ifiles = session.query(models.InternalFile) \ .filter(models.InternalFile.internaltip_id == models.WhistleblowerTip.id, models.WhistleblowerTip.receipt_hash == text_type(hashed_receipt, 'utf-8')) return [ models.serializers.serialize_ifile(session, ifile) for ifile in ifiles ]
def db_admin_update_user(session, state, tid, user_id, request, language): """ Updates the specified user. """ fill_localized_keys(request, models.User.localized_keys, language) user = models.db_get(session, models.User, models.User.tid == tid, models.User.id == user_id) user.update(request) password = request['password'] if password: user.password = security.hash_password(password, user.salt) user.password_change_date = datetime_now() # The various options related in manage PGP keys are used here. parse_pgp_options(state, user, request) if user.role == 'admin': db_refresh_memory_variables(session, [tid]) return user
from globaleaks.utils import security, tempdict, token, utility from globaleaks.utils.securetempfile import SecureTemporaryFile from globaleaks.utils.objectdict import ObjectDict from globaleaks.utils.structures import fill_localized_keys from globaleaks.utils.utility import datetime_null, datetime_now, datetime_to_ISO8601, \ log, sum_dicts from globaleaks.workers import process from globaleaks.workers.supervisor import ProcessSupervisor ## constants VALID_PASSWORD1 = u'ACollectionOfDiplomaticHistorySince_1966_ToThe_Pr esentDay#' VALID_PASSWORD2 = VALID_PASSWORD1 VALID_SALT1 = security.generateRandomSalt() VALID_SALT2 = security.generateRandomSalt() VALID_HASH1 = security.hash_password(VALID_PASSWORD1, VALID_SALT1) VALID_HASH2 = security.hash_password(VALID_PASSWORD2, VALID_SALT2) VALID_BASE64_IMG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=' INVALID_PASSWORD = u'antani' PGPKEYS = {} DATA_DIR = os.path.join(TEST_DIR, 'data') kp = os.path.join(DATA_DIR, 'gpg') for filename in os.listdir(kp): with open(os.path.join(kp, filename)) as pgp_file: PGPKEYS[filename] = text_type(pgp_file.read()) def deferred_sleep_mock(seconds): return
def db_create_submission(session, tid, request, uploaded_files, client_using_tor): answers = request['answers'] context, questionnaire = session.query(models.Context, models.Questionnaire) \ .filter(models.Context.id == request['context_id'], models.Questionnaire.id == models.Context.questionnaire_id, models.Questionnaire.tid.in_(set([1, tid]))).one_or_none() if not context: raise errors.ModelNotFound(models.Context) steps = db_get_questionnaire(session, tid, questionnaire.id, None)['steps'] questionnaire_hash = text_type(sha256(json.dumps(steps))) db_archive_questionnaire_schema(session, steps, questionnaire_hash) submission = models.InternalTip() submission.tid = tid submission.status = db_get_id_for_system_status(session, tid, 'new') submission.progressive = db_assign_submission_progressive(session, tid) if context.tip_timetolive > 0: submission.expiration_date = get_expiration(context.tip_timetolive) else: submission.expiration_date = datetime_never() # this is get from the client as it the only possibility possible # that would fit with the end to end submission. # the score is only an indicator and not a critical information so we can accept to # be fooled by the malicious user. submission.total_score = request['total_score'] # The status https is used to keep track of the security level adopted by the whistleblower submission.https = not client_using_tor submission.context_id = context.id submission.enable_two_way_comments = context.enable_two_way_comments submission.enable_two_way_messages = context.enable_two_way_messages submission.enable_attachments = context.enable_attachments whistleblower_identity = session.query(models.Field) \ .filter(models.Field.template_id == u'whistleblower_identity', models.Field.step_id == models.Step.id, models.Step.questionnaire_id == context.questionnaire_id).one_or_none() submission.enable_whistleblower_identity = whistleblower_identity is not None if submission.enable_whistleblower_identity and request['identity_provided']: submission.identity_provided = True submission.identity_provided_date = datetime_now() submission.questionnaire_hash = questionnaire_hash submission.preview = extract_answers_preview(steps, answers) session.add(submission) session.flush() receipt = text_type(generateRandomReceipt()) wbtip = models.WhistleblowerTip() wbtip.id = submission.id wbtip.tid = submission.tid wbtip.receipt_hash = hash_password(receipt, State.tenant_cache[tid].receipt_salt) session.add(wbtip) db_save_questionnaire_answers(session, tid, submission.id, answers) for filedesc in uploaded_files: new_file = models.InternalFile() new_file.tid = tid new_file.name = filedesc['name'] new_file.description = "" new_file.content_type = filedesc['type'] new_file.size = filedesc['size'] new_file.internaltip_id = submission.id new_file.submission = filedesc['submission'] new_file.filename = filedesc['filename'] session.add(new_file) log.debug("=> file associated %s|%s (%d bytes)", new_file.name, new_file.content_type, new_file.size) if context.maximum_selectable_receivers > 0 and \ len(request['receivers']) > context.maximum_selectable_receivers: raise errors.InputValidationError("selected an invalid number of recipients") rtips_count = 0 for receiver, user in session.query(models.Receiver, models.User) \ .filter(models.Receiver.id.in_(request['receivers']), models.ReceiverContext.receiver_id == models.Receiver.id, models.ReceiverContext.context_id == context.id, models.User.id == models.Receiver.id, models.UserTenant.user_id == models.User.id, models.UserTenant.tenant_id == tid): if user.pgp_key_public or State.tenant_cache[tid].allow_unencrypted: db_create_receivertip(session, receiver, submission) rtips_count += 1 if rtips_count == 0: raise errors.InputValidationError("need at least one recipient") log.debug("The finalized submission had created %d models.ReceiverTip(s)", rtips_count) return {'receipt': receipt}
def login(session, tid, username, password, receiver_second_login, receiver_auth_code, client_using_tor, client_ip, token=''): """ login returns a tuple (user_id, state, role, pcn, authCodePrepared) """ if token: user = session.query(User).filter(User.auth_token == token, \ User.state != u'disabled', \ User.tid == tid).one_or_none() else: user = session.query(User).filter(User.username == username, \ User.state != u'disabled', \ User.tid == tid).one_or_none() if user is None or (not token and not security.check_password( password, user.salt, user.password)): log.debug("Login: Invalid credentials") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication if not client_using_tor and not mystate.tenant_cache[tid]['https_' + user.role]: log.err("Denied login request over Web for role '%s'" % user.role) raise errors.TorNetworkRequired # Check if we're doing IP address checks today if mystate.tenant_cache[tid]['ip_filter_authenticated_enable']: ip_networks = parse_csv_ip_ranges_to_ip_networks( mystate.tenant_cache[tid]['ip_filter_authenticated']) client_ip = text_type(client_ip) client_ip_obj = ipaddress.ip_address(client_ip) # Safety check, we always allow localhost to log in success = False if client_ip_obj.is_loopback is True: success = True for ip_network in ip_networks: if client_ip_obj in ip_network: success = True if success is not True: raise errors.AccessLocationInvalid # se sono arrivato qui il primo login è andato a buon fine # il login (username, password) per un ricevente viene rieseguito anche al secondo passaggio # per motivi di sicurezza # A QUESTO PUNTO: # SE receiver2ndStepLoginState = 'N': # 1 - genero il codice # 2 - memorizzo record in ReceiverAuthCode # 3 - invio mail # ELSE: # verifico la correttenza del secondo codice if user.role == 'receiver': receiver = session.query(Receiver).filter( Receiver.id == user.id).one_or_none() if receiver.two_step_login_enabled and not user.password_change_needed: if receiver_second_login == 'first_login_to_complete': yyyy = str(datetime_now().year) mm = str(datetime_now().month).zfill(2) dd = str(datetime_now().day).zfill(2) result_query = session.query(ReceiverAuthCode).filter( ReceiverAuthCode.receiver_id == user.id, func.strftime("%Y-%m-%d", ReceiverAuthCode.creation_date) == yyyy + '-' + mm + '-' + dd).all() # genero il codice #chiamo la funzione generate_authcode_password che genera la password con l'utilizzo della funzione os.urandom #randnum = ''.join(["%s" % SystemRandom().randint(0, 9) for num in range(0, 12)]) randnum = generate_authcode_password(12) #print randnum log.debug(randnum[0:4] + ' ' + randnum[4:8] + ' ' + randnum[8:12]) # inserisco il record nel db newAuthCode = models.ReceiverAuthCode() newAuthCode.receiver_id = receiver.id newAuthCode.salt = security.generateRandomSalt() newAuthCode.auth_code = security.hash_password( randnum, newAuthCode.salt) session.add(newAuthCode) session.flush() # invio i tre pezzi del codice alle tre mail specificate nel profilo del ricevente email_prg = str(len(result_query) + 1) day = dd + '/' + mm + '/' + yyyy mystate.sendmail( 1, receiver.control_mail_1, "Receiver Auth Code #" + email_prg + " - " + day, randnum[0:4]) mystate.sendmail( 1, receiver.control_mail_2, "Receiver Auth Code #" + email_prg + " - " + day, randnum[4:8]) mystate.sendmail( 1, receiver.control_mail_3, "Receiver Auth Code #" + email_prg + " - " + day, randnum[8:12]) log.debug("Invio delle mail effettuato con successo") receiver_second_login = '******' elif receiver_second_login == 'second_login_to_complete': auth_code_item = session.query(ReceiverAuthCode).filter(ReceiverAuthCode.receiver_id == user.id) \ .order_by(ReceiverAuthCode.creation_date.desc()).first() # se non sono passati TOT minuti dall'ultimo codice emesso si può controllare la validità del codice if auth_code_item is not None and auth_code_item.is_valid and not is_expired( auth_code_item.creation_date, 0, AUTH_CODE_EXPIRATION_IN_MINUTES, 0, 0): # qui devo verificare che il codice inviato dall'utente sia uguale a una delle permutazioni dei tre blocchi # da quattro cifre che si ottengono dal codice salvato sul db firstBlock = receiver_auth_code[0:4] secondBlock = receiver_auth_code[4:8] thirdBlock = receiver_auth_code[8:12] combList = [] combList.insert(0, firstBlock + secondBlock + thirdBlock) combList.insert(1, firstBlock + thirdBlock + secondBlock) combList.insert(2, secondBlock + firstBlock + thirdBlock) combList.insert(3, secondBlock + thirdBlock + firstBlock) combList.insert(4, thirdBlock + firstBlock + secondBlock) combList.insert(5, thirdBlock + secondBlock + firstBlock) auth_code_match = False for authCode in combList: if security.check_password(authCode, auth_code_item.salt, auth_code_item.auth_code): auth_code_match = True # POSSO ANCHE FARE UNA UPDATE del campo is_valid PER IL RECORD UTILIZZATO NELLA VALIDAZIONE auth_code_item.is_valid = False session.add(auth_code_item) session.flush() #objs = session.query(ReceiverAuthCode).filter(ReceiverAuthCode.receiver_id == auth_code_item.receiver_id) \ # .order_by(ReceiverAuthCode.creation_date.desc(), ReceiverAuthCode.daily_prg.desc()) #for obj in objs: # session.delete(obj) # session.flush() #session.delete(auth_code_item) receiver_second_login = '******' break if not auth_code_match: log.debug("Login: Invalid authentication code") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication else: log.debug( "Login: authentication code is expired. Please repeat login" ) Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication else: log.debug( "receiver_auth_code diverso da first_login_to_complete e second_login_to_complete" ) receiver_second_login = '******' else: receiver_second_login = '******' #da tenere sotto controllo else: receiver_second_login = '******' # da tenere sotto controllo log.debug("Login: Success (%s)" % user.role) user.last_login = datetime_now() return user.id, user.state, user.role, user.password_change_needed, receiver_second_login
def test_pass_hash(self): dummy_password = "******" sure = hash_password(dummy_password, dummy_salt) not_sure = hash_password(dummy_password, dummy_salt) self.assertEqual(sure, not_sure)
def db_get_wbtip_by_receipt(session, tid, receipt): hashed_receipt = security.hash_password(receipt, State.tenant_cache[tid].receipt_salt) return session.query(InternalTip) \ .filter(InternalTip.receipt_hash == unicode(hashed_receipt), InternalTip.tid == tid).one_or_none()