def db_gen_user_keys(session, tid, user, password): """ Transaction generating and saving user keys :param session: An ORM session :param tid: A tenant ID :param user: A user object :param password: A user's password :return: A private key generated for the user """ enc_key = GCE.derive_key(password.encode(), user.salt) crypto_prv_key, user.crypto_pub_key = GCE.generate_keypair() user.crypto_bkp_key, user.crypto_rec_key = GCE.generate_recovery_key( crypto_prv_key) user.crypto_prv_key = Base64Encoder.encode( GCE.symmetric_encrypt(enc_key, crypto_prv_key)) # Create an escrow backup for the root tenant tid_1_escrow = config.ConfigFactory(session, 1).get_val('crypto_escrow_pub_key') if tid_1_escrow: user.crypto_escrow_bkp1_key = Base64Encoder.encode( GCE.asymmetric_encrypt(tid_1_escrow, crypto_prv_key)) # Create an escrow backup for the actual tenant tid_n_escrow = config.ConfigFactory(session, tid).get_val('crypto_escrow_pub_key') if tid_n_escrow: user.crypto_escrow_bkp2_key = Base64Encoder.encode( GCE.asymmetric_encrypt(tid_n_escrow, crypto_prv_key)) return crypto_prv_key
def set_user_password(tid, user, password, cc): # Regenerate the password hash only if different from the best choice on the platform if user.hash_alg != 'ARGON2': user.hash_alg = 'ARGON2' user.salt = GCE.generate_salt() password_hash = GCE.hash_password(password, user.salt) # Check that the new password is different form the current password if user.password == password_hash: raise errors.PasswordReuseError user.password = password_hash user.password_change_date = datetime_now() if not State.tenant_cache[tid].encryption and cc == '': return None enc_key = GCE.derive_key(password.encode(), user.salt) if not cc: # The first password change triggers the generation # of the user encryption private key and its backup cc, user.crypto_pub_key = GCE.generate_keypair() user.crypto_bkp_key, user.crypto_rec_key = GCE.generate_recovery_key(cc) user.crypto_prv_key = Base64Encoder.encode(GCE.symmetric_encrypt(enc_key, cc)) if State.tenant_cache[1].crypto_escrow_pub_key: user.crypto_escrow_bkp1_key = Base64Encoder.encode(GCE.asymmetric_encrypt(State.tenant_cache[1].crypto_escrow_pub_key, cc)) if State.tenant_cache[tid].crypto_escrow_pub_key: user.crypto_escrow_bkp2_key = Base64Encoder.encode(GCE.asymmetric_encrypt(State.tenant_cache[tid].crypto_escrow_pub_key, cc)) return cc
def test_recovery_key(self): prv_key, _ = GCE.generate_keypair() bck_key, rec_key = GCE.generate_recovery_key(prv_key) plain_rec_key = GCE.asymmetric_decrypt(prv_key, Base64Encoder.decode(rec_key)) x = GCE.symmetric_decrypt(plain_rec_key, Base64Encoder.decode(bck_key)) self.assertEqual(x, prv_key)
def db_admin_update_user(session, tid, user_session, user_id, request, language): """ Transaction for updating an existing user :param session: An ORM session :param tid: A tenant ID :param user_session: The current user session :param user_id: The ID of the user to update :param request: The request data :param language: The language of the request :return: The serialized descriptor of the updated object """ 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 == request['username'], models.User.tid == tid).one_or_none() if check is not None: raise errors.InputValidationError('Username already in use') user.update(request) password = request['password'] if password and (not user.crypto_pub_key or user_session.ek): if user.crypto_pub_key and user_session.ek: enc_key = GCE.derive_key(password.encode(), user.salt) crypto_escrow_prv_key = GCE.asymmetric_decrypt( user_session.cc, Base64Encoder.decode(user_session.ek)) if tid == 1: user_cc = GCE.asymmetric_decrypt( crypto_escrow_prv_key, Base64Encoder.decode(user.crypto_escrow_bkp1_key)) else: user_cc = GCE.asymmetric_decrypt( crypto_escrow_prv_key, Base64Encoder.decode(user.crypto_escrow_bkp2_key)) user.crypto_prv_key = Base64Encoder.encode( GCE.symmetric_encrypt(enc_key, user_cc)) if user.hash_alg != 'ARGON2': user.hash_alg = 'ARGON2' user.salt = GCE.generate_salt() user.password = GCE.hash_password(password, user.salt) user.password_change_date = datetime_now() user.password_change_needed = True # The various options related in manage PGP keys are used here. parse_pgp_options(user, request) return user_serialize_user(session, user, language)
def validate_password_reset(session, reset_token, auth_code, recovery_key): """ Retrieves a user given a password reset validation token :param session: An ORM session :param reset_token: A reset token :param auth_code: A two factor authentication code (optional) :param recovery_key: An encryption recovery key (optional) :return: A descriptor describing the result of the operation """ now = datetime.now() prv_key = '' user = session.query(models.User).filter( models.User.reset_password_token == reset_token, models.User.reset_password_date >= now - timedelta(hours=72) ).one_or_none() # If the authentication token is invalid if user is None: return {'status': 'invalid_reset_token_provided'} # If encryption is enabled require the recovery key if user.crypto_prv_key: try: x = State.TempKeys.pop(user.id, None) if x: enc_key = GCE.derive_key(reset_token.encode(), user.salt) prv_key = GCE.symmetric_decrypt(enc_key, Base64Encoder.decode(x)) else: recovery_key = recovery_key.replace('-', '').upper() + '====' recovery_key = Base32Encoder.decode(recovery_key.encode()) prv_key = GCE.symmetric_decrypt(recovery_key, Base64Encoder.decode(user.crypto_bkp_key)) except: return {'status': 'require_recovery_key'} elif user.two_factor_enable: two_factor_secret = user.two_factor_secret if not pyotp.TOTP(two_factor_secret).verify(auth_code, valid_window=1): return {'status': 'require_two_factor_authentication'} # Token is used, void it out user.reset_password_token = None user.reset_password_date = now # Require password change user.password_change_needed = True session = Sessions.new(user.tid, user.id, user.tid, user.role, user.password_change_needed, user.two_factor_enable, prv_key, user.crypto_escrow_prv_key) return {'status': 'success', 'token': session.id}
def generate_password_reset_token(session, tid, user_session, user_id): user = session.query(User).filter(User.tid == tid, User.id == user_id).one_or_none() if user is None: return db_generate_password_reset_token(session, user) if user_session.ek and user.crypto_pub_key: crypto_escrow_prv_key = GCE.asymmetric_decrypt(user_session.cc, Base64Encoder.decode(user_session.ek)) user_cc = GCE.asymmetric_decrypt(crypto_escrow_prv_key, Base64Encoder.decode(user.crypto_escrow_bkp1_key)) enc_key = GCE.derive_key(user.reset_password_token.encode(), user.salt) key = Base64Encoder.encode(GCE.symmetric_encrypt(enc_key, user_cc)) State.TempKeys[user_id] = TempKey(key)
def db_update_node(session, tid, user_session, request, language): """ Transaction to update the node configuration :param session: An ORM session :param tid: A tenant ID :param user_session: The current user session :param request: The request data :param language: the language in which to localize data :return: Return the serialized configuration for the specified tenant """ config = ConfigFactory(session, tid) enable_escrow = not config.get_val('escrow') and request.get('escrow', False) disable_escrow = user_session.ek and config.get_val('escrow') and not request.get('escrow', False) config.update('node', request) if request['enable_ricochet_panel'] and not request['ricochet_address']: request['enable_ricochet_panel'] = False # Validate that IP addresses/ranges we're getting are goo if 'ip_filter_admin' in request and request['ip_filter_admin_enable'] and request['ip_filter_admin']: parse_csv_ip_ranges_to_ip_networks(request['ip_filter_admin']) if 'languages_enabled' in request and 'default_language' in request: db_update_enabled_languages(session, tid, request['languages_enabled'], request['default_language']) if language in db_get_languages(session, tid): ConfigL10NFactory(session, tid).update('node', request, language) if enable_escrow: crypto_escrow_prv_key, State.tenant_cache[tid].crypto_escrow_pub_key = GCE.generate_keypair() user = db_get(session, models.User, models.User.id == user_session.user_id) user.crypto_escrow_prv_key = Base64Encoder.encode(GCE.asymmetric_encrypt(user.crypto_pub_key, crypto_escrow_prv_key)) if tid == 1: session.query(models.User).update({'password_change_needed': True}, synchronize_session=False) else: session.query(models.User).filter(models.User.tid == tid).update({'password_change_needed': True}, synchronize_session=False) if disable_escrow: if tid == 1: session.query(models.User).update({'crypto_escrow_bkp1_key': ''}, synchronize_session=False) else: session.query(models.User).update({'crypto_escrow_bkp2_key': ''}, synchronize_session=False) session.query(models.User).filter(models.User.tid == tid).update({'crypto_escrow_prv_key': ''}, synchronize_session=False) config.set_val('crypto_escrow_pub_key', State.tenant_cache[tid].crypto_escrow_pub_key) db_refresh_memory_variables(session, [tid]) if tid == 1: log.setloglevel(config.get_val('log_level')) return db_admin_serialize_node(session, tid, language)
def login_whistleblower(session, tid, receipt): """ Login transaction for whistleblowers' access :param session: An ORM session :param tid: A tenant ID :param receipt: A provided receipt :return: Returns a user session in case of success """ x = None algorithms = [x[0] for x in session.query(WhistleblowerTip.hash_alg).filter(WhistleblowerTip.tid == tid).distinct()] if algorithms: hashes = [GCE.hash_password(receipt, State.tenant_cache[tid].receipt_salt, alg) for alg in algorithms] x = session.query(WhistleblowerTip, InternalTip) \ .filter(WhistleblowerTip.receipt_hash.in_(hashes), WhistleblowerTip.tid == tid, InternalTip.id == WhistleblowerTip.id).one_or_none() if x is None: login_failure(tid, 1) wbtip = x[0] itip = x[1] itip.wb_last_access = datetime_now() crypto_prv_key = '' if wbtip.crypto_prv_key: user_key = GCE.derive_key(receipt.encode(), State.tenant_cache[tid].receipt_salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, Base64Encoder.decode(wbtip.crypto_prv_key)) return Sessions.new(tid, wbtip.id, tid, 'whistleblower', False, False, crypto_prv_key, '')
def login(session, tid, username, password, authcode, client_using_tor, client_ip): """ Login transaction for users' access :param session: An ORM session :param tid: A tenant ID :param username: A provided username :param password: A provided password :param authcode: A provided authcode :param client_using_tor: A boolean signaling Tor usage :param client_ip: The client IP :return: Returns a user session in case of success """ user = None for u in session.query(User).filter(User.username == username, User.state == 'enabled', User.tid == tid): if GCE.check_password(u.hash_alg, password, u.salt, u.password): user = u break if user is None: log.debug("Login: Invalid credentials") login_error(tid) connection_check(tid, client_ip, user.role, client_using_tor) crypto_prv_key = '' if user.crypto_prv_key: user_key = GCE.derive_key(password.encode(), user.salt) crypto_prv_key = GCE.symmetric_decrypt( user_key, Base64Encoder.decode(user.crypto_prv_key)) elif State.tenant_cache[tid].encryption: # Force the password change on which the user key will be created user.password_change_needed = True # Require password change if password change threshold is exceeded if State.tenant_cache[tid].password_change_period > 0 and \ user.password_change_date < datetime_now() - timedelta(days=State.tenant_cache[tid].password_change_period): user.password_change_needed = True if user.two_factor_enable: if authcode != '': # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec if not pyotp.TOTP(user.two_factor_secret).verify(authcode, valid_window=1): raise errors.InvalidTwoFactorAuthCode else: raise errors.TwoFactorAuthCodeRequired user.last_login = datetime_now() return Sessions.new(tid, user.id, user.tid, user.role, user.password_change_needed, user.two_factor_enable, crypto_prv_key, user.crypto_escrow_prv_key)
def db_admin_update_user(session, tid, user_session, user_id, request, language): """ Transaction for updating an existing user :param session: An ORM session :param tid: A tenant ID :param user_session: The current user session :param user_id: The ID of the user to update :param request: The request data :param language: The language of the request :return: The serialized descriptor of the updated object """ fill_localized_keys(request, models.User.localized_keys, language) user = db_get_user(session, tid, user_id) user.update(request) password = request['password'] if password and (not user.crypto_pub_key or user_session.ek): if user.crypto_pub_key and user_session.ek: enc_key = GCE.derive_key(password.encode(), user.salt) crypto_escrow_prv_key = GCE.asymmetric_decrypt(user_session.cc, Base64Encoder.decode(user_session.ek)) if user_session.user_tid == 1: user_cc = GCE.asymmetric_decrypt(crypto_escrow_prv_key, Base64Encoder.decode(user.crypto_escrow_bkp1_key)) else: user_cc = GCE.asymmetric_decrypt(crypto_escrow_prv_key, Base64Encoder.decode(user.crypto_escrow_bkp2_key)) user.crypto_prv_key = Base64Encoder.encode(GCE.symmetric_encrypt(enc_key, user_cc)) if user.hash_alg != 'ARGON2': user.hash_alg = 'ARGON2' user.salt = GCE.generate_salt() user.password = GCE.hash_password(password, user.salt) user.password_change_date = datetime_now() State.log(tid=tid, type='change_password', user_id=user_session.user_id, object_id=user_id) # The various options related in manage PGP keys are used here. parse_pgp_options(user, request) return user_serialize_user(session, user, language)
def db_create_receivertip(session, receiver, internaltip, can_access_whistleblower_identity, enc_key): """ Create a receiver tip for the specified receiver """ receivertip = models.ReceiverTip() receivertip.internaltip_id = internaltip.id receivertip.receiver_id = receiver.id receivertip.can_access_whistleblower_identity = can_access_whistleblower_identity receivertip.crypto_tip_prv_key = Base64Encoder.encode(enc_key) session.add(receivertip)
def toggle_escrow(session, tid, user_session, user_id): """ Transaction to toggle key escrow access for user an user given its id :param session: An ORM session :param tid: A tenant ID :param user_session: The current user session :param user_id: The user for which togling the key escrow access """ if user_session.user_id == user_id or not user_session.ek: return user = db_get_user(session, tid, user_id) if not user.crypto_pub_key: return if not user.crypto_escrow_prv_key: crypto_escrow_prv_key = GCE.asymmetric_decrypt(user_session.cc, Base64Encoder.decode(user_session.ek)) user.crypto_escrow_prv_key = Base64Encoder.encode(GCE.asymmetric_encrypt(user.crypto_pub_key, crypto_escrow_prv_key)) else: user.crypto_escrow_prv_key = ''
def get_recovery_key(session, tid, user_id, user_cc): """ Transaction to get a user recovery key :param session: An ORM session :param tid: The tenant ID :param user_id: The user ID :param user_cc: The user key :return: The recovery key encoded base32 """ user = db_get_user(session, tid, user_id) if not user.crypto_rec_key: return '' return Base32Encoder.encode(GCE.asymmetric_decrypt(user_cc, Base64Encoder.decode(user.crypto_rec_key.encode()))).replace(b'=', b'')
def get_tip_export(session, tid, user_id, rtip_id, language): rtip, itip = db_access_rtip(session, tid, user_id, rtip_id) user, context = session.query(models.User, models.Context) \ .filter(models.User.id == rtip.receiver_id, models.Context.id == models.InternalTip.context_id, models.InternalTip.id == rtip.internaltip_id, models.User.tid == tid).one() rtip_dict = serialize_rtip(session, rtip, itip, language) return { 'type': 'export_template', 'node': db_admin_serialize_node(session, tid, language), 'notification': db_get_notification(session, tid, language), 'tip': rtip_dict, 'crypto_tip_prv_key': Base64Encoder.decode(rtip.crypto_tip_prv_key), 'user': user_serialize_user(session, user, language), 'context': admin_serialize_context(session, context, language), 'submission_statuses': db_get_submission_statuses(session, tid, language) }
################################################################################ # BEGIN MOCKS NECESSARY FOR DETERMINISTIC ENCRYPTION VALID_PASSWORD1 = 'ACollectionOfDiplomaticHistorySince_1966_ToThe_Pr esentDay#' VALID_PASSWORD2 = VALID_PASSWORD1 VALID_SALT1 = GCE.generate_salt() VALID_SALT2 = GCE.generate_salt() VALID_HASH1 = GCE.hash_password(VALID_PASSWORD1, VALID_SALT1) VALID_HASH2 = GCE.hash_password(VALID_PASSWORD2, VALID_SALT2) VALID_BASE64_IMG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=' INVALID_PASSWORD = '******' KEY = GCE.generate_key() USER_KEY = GCE.derive_key(VALID_PASSWORD1, VALID_SALT1) USER_PRV_KEY, USER_PUB_KEY = GCE.generate_keypair() USER_PRV_KEY_ENC = Base64Encoder.encode(GCE.symmetric_encrypt(USER_KEY, USER_PRV_KEY)) USER_BKP_KEY, USER_REC_KEY = GCE.generate_recovery_key(USER_PRV_KEY) USER_REC_KEY_PLAIN = GCE.asymmetric_decrypt(USER_PRV_KEY, Base64Encoder.decode(USER_REC_KEY)) USER_REC_KEY_PLAIN = Base32Encoder.encode(USER_REC_KEY_PLAIN).replace(b'=', b'').decode('utf-8') GCE_orig_generate_key = GCE.generate_key GCE_orig_generate_keypair = GCE.generate_keypair def GCE_mock_generate_key(): return KEY def GCE_mock_generate_keypair(): return USER_PRV_KEY, USER_PUB_KEY
def db_create_submission(session, tid, request, token, client_using_tor): tenant = db_get(session, models.Tenant, models.Tenant.id == tid) context, questionnaire = db_get( session, (models.Context, models.Questionnaire), (models.Context.id == request['context_id'], models.Questionnaire.id == models.Context.questionnaire_id)) receivers = request['receivers'] answers = request['answers'] steps = db_get_questionnaire(session, tid, questionnaire.id, None)['steps'] questionnaire_hash = db_archive_questionnaire_schema(session, steps) preview = extract_answers_preview(steps, answers) crypto_is_available = State.tenant_cache[tid].encryption crypto_tip_pub_key = '' if crypto_is_available: crypto_tip_prv_key, crypto_tip_pub_key = GCE.generate_keypair() receivers = [r[0] for r in session.query(models.User.id) \ .filter(models.User.id.in_(receivers), models.User.crypto_pub_key != '')] if not request['receivers']: raise errors.InputValidationError( "Unable to deliver the submission to at least one recipient") if 0 < context.maximum_selectable_receivers < len(request['receivers']): raise errors.InputValidationError( "The number of recipients selected exceed the configured limit") itip = models.InternalTip() itip.tid = tid itip.status = 'new' itip.crypto_tip_pub_key = crypto_tip_pub_key itip.progressive = db_assign_submission_progressive(session, tid) itip.additional_questionnaire_id = context.additional_questionnaire_id if context.tip_timetolive > 0: itip.expiration_date = get_expiration(context.tip_timetolive) # Evaluate the score level itip.total_score = request['total_score'] # The status https is used to keep track of the security level adopted by the whistleblower itip.https = not client_using_tor itip.mobile = request['mobile'] itip.context_id = context.id itip.enable_two_way_comments = context.enable_two_way_comments itip.enable_two_way_messages = context.enable_two_way_messages itip.enable_attachments = context.enable_attachments x = session.query(models.Field, models.FieldAttr.value) \ .filter(models.Field.template_id == 'whistleblower_identity', models.Field.step_id == models.Step.id, models.Step.questionnaire_id == context.questionnaire_id, models.FieldAttr.field_id == models.Field.id, models.FieldAttr.name == 'visibility_subject_to_authorization').one_or_none() whistleblower_identity = None can_access_whistleblower_identity = True if x: whistleblower_identity = x[0] can_access_whistleblower_identity = not x[1] itip.enable_whistleblower_identity = whistleblower_identity is not None session.add(itip) session.flush() # Evaluate if the whistleblower tip should be generated if ((not State.tenant_cache[tid].enable_scoring_system) or (context.score_threshold_receipt == 0) or (context.score_threshold_receipt == 1 and itip.total_score >= 2) or (context.score_threshold_receipt == 2 and itip.total_score == 3)): receipt = GCE.generate_receipt() receipt_salt = State.tenant_cache[tid].receipt_salt wbtip = models.WhistleblowerTip() wbtip.id = itip.id wbtip.tid = tid wbtip.hash_alg = 'ARGON2' wbtip.receipt_hash = GCE.hash_password(receipt, receipt_salt) # Evaluate if the whistleblower tip should be encrypted if crypto_is_available: crypto_tip_prv_key, itip.crypto_tip_pub_key = GCE.generate_keypair( ) wb_key = GCE.derive_key(receipt.encode(), receipt_salt) wb_prv_key, wb_pub_key = GCE.generate_keypair() wbtip.crypto_prv_key = Base64Encoder.encode( GCE.symmetric_encrypt(wb_key, wb_prv_key)) wbtip.crypto_pub_key = wb_pub_key wbtip.crypto_tip_prv_key = Base64Encoder.encode( GCE.asymmetric_encrypt(wb_pub_key, crypto_tip_prv_key)) session.add(wbtip) else: receipt = '' # Apply special handling to the whistleblower identity question if itip.enable_whistleblower_identity and request[ 'identity_provided'] and answers[whistleblower_identity.id]: if crypto_is_available: wbi = base64.b64encode( GCE.asymmetric_encrypt( itip.crypto_tip_pub_key, json.dumps(answers[whistleblower_identity.id] [0]).encode())).decode() else: wbi = answers[whistleblower_identity.id][0] answers[whistleblower_identity.id] = '' db_set_internaltip_data(session, itip.id, 'whistleblower_identity', wbi) db_save_plaintext_answers(session, tid, itip.id, answers, crypto_is_available) if crypto_is_available: preview = base64.b64encode( GCE.asymmetric_encrypt( itip.crypto_tip_pub_key, json.dumps(preview, cls=JSONEncoder).encode())).decode() answers = base64.b64encode( GCE.asymmetric_encrypt( itip.crypto_tip_pub_key, json.dumps(answers, cls=JSONEncoder).encode())).decode() itip.preview = preview db_set_internaltip_answers(session, itip.id, questionnaire_hash, answers) for uploaded_file in token.uploaded_files: if not itip.enable_attachments: break if uploaded_file['id'] in request['removed_files']: continue if crypto_is_available: for k in ['name', 'type', 'size']: uploaded_file[k] = base64.b64encode( GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, str(uploaded_file[k]))) new_file = models.InternalFile() new_file.tid = tid new_file.name = uploaded_file['name'] new_file.content_type = uploaded_file['type'] new_file.size = uploaded_file['size'] new_file.internaltip_id = itip.id new_file.filename = uploaded_file['filename'] new_file.submission = uploaded_file['submission'] session.add(new_file) for user in session.query(models.User).filter( models.User.id.in_(request['receivers'])): _tip_key = b'' if crypto_is_available: if not user.crypto_pub_key: continue _tip_key = GCE.asymmetric_encrypt(user.crypto_pub_key, crypto_tip_prv_key) db_create_receivertip(session, user, itip, can_access_whistleblower_identity, _tip_key) return {'receipt': receipt, 'score': itip.total_score}
def db_wizard(session, tid, hostname, request): """ Transaction for the handling of wizard request :param session: An ORM session :param tid: A tenant ID :param request: A user request """ language = request['node_language'] node = config.ConfigFactory(session, tid) if tid == 1: root_tenant_node = node encryption = True else: root_tenant_node = node encryption = root_tenant_node.get_val('encryption') if node.get_val('wizard_done'): log.err("DANGER: Wizard already initialized!", tid=tid) raise errors.ForbiddenOperation db_update_enabled_languages(session, tid, [language], language) node.set_val('encryption', encryption) node.set_val('name', request['node_name']) node.set_val('default_language', language) node.set_val('wizard_done', True) node.set_val('enable_developers_exception_notification', request['enable_developers_exception_notification']) node.set_val('hostname', hostname) node_l10n = config.ConfigL10NFactory(session, tid) node_l10n.set_val('header_title_homepage', language, request['node_name']) profiles.load_profile(session, tid, request['profile']) if encryption: crypto_escrow_prv_key, crypto_escrow_pub_key = GCE.generate_keypair() node.set_val('crypto_escrow_pub_key', crypto_escrow_pub_key) admin_desc = models.User().dict(language) admin_desc['username'] = request['admin_username'] admin_desc['name'] = request['admin_name'] admin_desc['password'] = request['admin_password'] admin_desc['name'] = request['admin_name'] admin_desc['mail_address'] = request['admin_mail_address'] admin_desc['language'] = language admin_desc['role'] = 'admin' admin_desc['pgp_key_remove'] = False admin_user = db_create_user(session, tid, admin_desc, language) admin_user.password = GCE.hash_password(request['admin_password'], admin_user.salt) admin_user.password_change_needed = False admin_user.password_change_date = datetime_now() if encryption: db_gen_user_keys(session, tid, admin_user, request['admin_password']) admin_user.crypto_escrow_prv_key = Base64Encoder.encode( GCE.asymmetric_encrypt(admin_user.crypto_pub_key, crypto_escrow_prv_key)) receiver_user = None if not request['skip_recipient_account_creation']: receiver_desc = models.User().dict(language) receiver_desc['username'] = request['receiver_username'] receiver_desc['name'] = request['receiver_name'] receiver_desc['password'] = request['receiver_password'] receiver_desc['mail_address'] = request['receiver_mail_address'] receiver_desc['language'] = language receiver_desc['role'] = 'receiver' receiver_desc['pgp_key_remove'] = False receiver_desc['send_account_activation_link'] = receiver_desc[ 'password'] == '' receiver_user = db_create_user(session, tid, receiver_desc, language) if receiver_desc['password']: receiver_user.password = GCE.hash_password( receiver_desc['password'], receiver_user.salt) if encryption: db_gen_user_keys(session, tid, receiver_user, receiver_desc['password']) context_desc = models.Context().dict(language) context_desc['name'] = 'Default' context_desc['status'] = 'enabled' context_desc['receivers'] = [receiver_user.id] if receiver_user else [] context = db_create_context(session, tid, context_desc, language) # Root tenants initialization terminates here if tid == 1: db_refresh_memory_variables(session, [tid]) return # Secondary tenants initialization starts here tenant = models.db_get(session, models.Tenant, models.Tenant.id == tid) tenant.label = request['node_name'] mode = node.get_val('mode') if mode not in ['default', 'demo']: node.set_val( 'hostname', tenant.subdomain + '.' + root_tenant_node.get_val('rootdomain')) for varname in [ 'reachable_via_web', 'enable_receipt_hint', 'disable_privacy_badge', 'simplified_login', 'can_delete_submission', 'can_postpone_expiration', 'anonymize_outgoing_connections', 'frame_ancestors', 'password_change_period', 'default_questionnaire', 'enable_password_reset' ]: node.set_val(varname, root_tenant_node.get_val(varname)) context.questionnaire_id = root_tenant_node.get_val( 'default_questionnaire') # Set data retention policy to 18 months context.tip_timetolive = 540 # Delete the admin user request['admin_password'] = '' session.delete(admin_user) if receiver_user is not None: # Enable the recipient user to configure platform general settings receiver_user.can_edit_general_settings = True # Set the recipient name equal to the node name receiver_user.name = receiver_user.public_name = request[ 'node_name'] # Apply the specific fixes related to whistleblowing.it projects if mode == 'whistleblowing.it': node.set_val('simplified_login', True) node.set_val('tor', False) db_refresh_memory_variables(session, [tid])
################################################################################ # BEGIN MOCKS NECESSARY FOR DETERMINISTIC ENCRYPTION VALID_PASSWORD1 = 'ACollectionOfDiplomaticHistorySince_1966_ToThe_Pr esentDay#' VALID_PASSWORD2 = VALID_PASSWORD1 VALID_SALT1 = GCE.generate_salt() VALID_SALT2 = GCE.generate_salt() VALID_HASH1 = GCE.hash_password(VALID_PASSWORD1, VALID_SALT1) VALID_HASH2 = GCE.hash_password(VALID_PASSWORD2, VALID_SALT2) VALID_BASE64_IMG = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII=' INVALID_PASSWORD = '******' KEY = GCE.generate_key() USER_KEY = GCE.derive_key(VALID_PASSWORD1, VALID_SALT1) USER_PRV_KEY, USER_PUB_KEY = GCE.generate_keypair() USER_PRV_KEY_ENC = Base64Encoder.encode( GCE.symmetric_encrypt(USER_KEY, USER_PRV_KEY)) USER_BKP_KEY, USER_REC_KEY = GCE.generate_recovery_key(USER_PRV_KEY) USER_REC_KEY_PLAIN = GCE.asymmetric_decrypt(USER_PRV_KEY, Base64Encoder.decode(USER_REC_KEY)) USER_REC_KEY_PLAIN = Base32Encoder.encode(USER_REC_KEY_PLAIN).replace( b'=', b'').decode('utf-8') GCE_orig_generate_key = GCE.generate_key GCE_orig_generate_keypair = GCE.generate_keypair def GCE_mock_generate_key(): return KEY def GCE_mock_generate_keypair(): return USER_PRV_KEY, USER_PUB_KEY
def login(session, tid, username, password, authcode, client_using_tor, client_ip): """ Login transaction for users' access :param session: An ORM session :param tid: A tenant ID :param username: A provided username :param password: A provided password :param authcode: A provided authcode :param client_using_tor: A boolean signaling Tor usage :param client_ip: The client IP :return: Returns a user session in case of success """ user = None users = session.query(User).filter(User.username == username, User.state != 'disabled', User.tid == tid).distinct() for u in users: if GCE.check_password(u.hash_alg, password, u.salt, u.password): user = u break # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563 if State.tenant_cache[1].creation_date < 1551740400: u_password = '******'' + u.password + '\'' if GCE.check_password(u.hash_alg, password, u.salt, u_password): user = u break if user is None: log.debug("Login: Invalid credentials") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication connection_check(client_ip, tid, user.role, client_using_tor) crypto_prv_key = '' if user.crypto_prv_key: user_key = GCE.derive_key(password.encode(), user.salt) crypto_prv_key = GCE.symmetric_decrypt( user_key, Base64Encoder.decode(user.crypto_prv_key)) elif State.tenant_cache[tid].encryption: # Force the password change on which the user key will be created user.password_change_needed = True if user.two_factor_enable: if authcode != '': # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec if not pyotp.TOTP(user.two_factor_secret).verify(authcode, valid_window=1): raise errors.InvalidTwoFactorAuthCode else: raise errors.TwoFactorAuthCodeRequired user.last_login = datetime_now() return Sessions.new(tid, user.id, user.tid, user.role, user.password_change_needed, user.two_factor_enable, crypto_prv_key, user.crypto_escrow_prv_key)