def login_whistleblower(session, tid, receipt): """ login_whistleblower returns a session """ x = None algorithms = [x[0] for x in session.query(WhistleblowerTip.hash_alg).filter(WhistleblowerTip.tid == tid).distinct()] if algorithms: hashes = [] for alg in algorithms: hashes.append(GCE.hash_password(receipt, State.tenant_cache[tid].receipt_salt, alg)) x = session.query(WhistleblowerTip, InternalTip) \ .filter(WhistleblowerTip.receipt_hash.in_(hashes), WhistleblowerTip.tid == tid, InternalTip.id == WhistleblowerTip.id, InternalTip.tid == WhistleblowerTip.tid).one_or_none() if x is None: log.debug("Whistleblower login: Invalid receipt") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication wbtip = x[0] itip = x[1] itip.wb_last_access = datetime_now() crypto_prv_key = '' if State.tenant_cache[1].encryption and wbtip.crypto_prv_key: user_key = GCE.derive_key(receipt.encode('utf-8'), State.tenant_cache[tid].receipt_salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, wbtip.crypto_prv_key) return Sessions.new(tid, wbtip.id, 'whistleblower', False, crypto_prv_key)
def login_whistleblower(session, tid, receipt): """ login_whistleblower returns a session """ x = None algorithms = [ x[0] for x in session.query(WhistleblowerTip.hash_alg).filter( WhistleblowerTip.tid == tid).distinct() ] if algorithms: hashes = [] for alg in algorithms: hashes.append( GCE.hash_password(receipt, State.tenant_cache[tid].receipt_salt, alg)) x = session.query(WhistleblowerTip, InternalTip) \ .filter(WhistleblowerTip.receipt_hash.in_(hashes), WhistleblowerTip.tid == tid, InternalTip.id == WhistleblowerTip.id, InternalTip.tid == WhistleblowerTip.tid).one_or_none() if x is None: log.debug("Whistleblower login: Invalid receipt") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication wbtip = x[0] itip = x[1] itip.wb_last_access = datetime_now() crypto_prv_key = '' if State.tenant_cache[tid].encryption and wbtip.crypto_prv_key: user_key = GCE.derive_key(receipt.encode('utf-8'), State.tenant_cache[tid].receipt_salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, wbtip.crypto_prv_key) return Sessions.new(tid, wbtip.id, tid, 'whistleblower', False, False, crypto_prv_key)
def validate_password_reset(session, tid, reset_token, auth_code, recovery_key): """Retrieves a user given a password reset validation token""" 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: recovery_key = recovery_key.replace('-', '').upper() + '====' recovery_key = Base32Encoder().decode(recovery_key.encode('utf-8')) prv_key = GCE.symmetric_decrypt(recovery_key, user.crypto_bkp_key) except: return {'status': 'require_recovery_key'} elif user.two_factor_enable: two_factor_secret = user.two_factor_secret.decode('utf-8') 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 user.password_change_needed = True session = Sessions.new(tid, user.id, user.tid, user.role, user.password_change_needed, user.two_factor_enable, prv_key) return {'status': 'success', 'token': session.id}
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, InternalTip.tid == WhistleblowerTip.tid).one_or_none() if x is None: log.debug("Whistleblower login: Invalid receipt") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication 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 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, rec_key) x = GCE.symmetric_decrypt(plain_rec_key, bck_key) self.assertEqual(x, prv_key)
def test_crypto_generate_key_encrypt_decrypt_key(self): enc_key = GCE.generate_key() enc = GCE.symmetric_encrypt(enc_key, message) dec = GCE.symmetric_decrypt(enc_key, enc) self.assertEqual(dec, message)
def test_generate_keypair(self): key = GCE.generate_key() prv_key, pub_key = GCE.generate_keypair() prv_key_enc = GCE.symmetric_encrypt(key, prv_key) self.assertEqual(prv_key, GCE.symmetric_decrypt(key, prv_key_enc))
def login(session, tid, username, password, authcode, client_using_tor, client_ip): """ login returns a session """ user = None users = session.query(User).filter(User.username == username, User.state != u'disabled', UserTenant.user_id == User.id, UserTenant.tenant_id == 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) if State.tenant_cache[1].two_factor_auth and user.last_login != datetime_null(): token = TwoFactorTokens.get(user.id) if token is not None and authcode != '': if token.token == authcode: TwoFactorTokens.revoke(user.id) else: raise errors.InvalidTwoFactorAuthCode elif token is None and authcode == '': token = TwoFactorTokens.new(user.id) data = { 'type': '2fa', 'authcode': str(token.token) } data['node'] = db_admin_serialize_node(session, tid, user.language) data['notification'] = db_get_notification(session, tid, user.language) subject, body = Templating().get_mail_subject_and_body(data) State.sendmail(1, user.mail_address, subject, body) raise errors.TwoFactorAuthCodeRequired else: raise errors.TwoFactorAuthCodeRequired user.last_login = datetime_now() crypto_prv_key = '' if State.tenant_cache[tid].encryption: if user.crypto_prv_key: user_key = GCE.derive_key(password.encode('utf-8'), user.salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key) else: # Force the password change on which the user key will be created user.password_change_needed = True return Sessions.new(tid, user.id, user.tid, user.role, user.password_change_needed, 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 # 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(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 login(session, tid, username, password, authcode, client_using_tor, client_ip): """ login returns a session """ user = None users = session.query(User).filter(User.username == username, User.state != u'disabled', UserTenant.user_id == User.id, UserTenant.tenant_id == 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 < datetime.timestamp(datetime(2019, 5, 3, 0, 0)): 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) if State.tenant_cache[1].two_factor_auth and user.last_login != datetime_null(): token = TwoFactorTokens.get(user.id) if token is not None and authcode != '': if token.token == authcode: TwoFactorTokens.revoke(user.id) else: raise errors.InvalidTwoFactorAuthCode elif token is None and authcode == '': token = TwoFactorTokens.new(user.id) data = { 'type': '2fa', 'authcode': str(token.token) } data['node'] = db_admin_serialize_node(session, tid, user.language) data['notification'] = db_get_notification(session, tid, user.language) subject, body = Templating().get_mail_subject_and_body(data) State.sendmail(1, user.mail_address, subject, body) raise errors.TwoFactorAuthCodeRequired else: raise errors.TwoFactorAuthCodeRequired user.last_login = datetime_now() crypto_prv_key = '' if State.tenant_cache[1].encryption and user.crypto_prv_key: user_key = GCE.derive_key(password.encode('utf-8'), user.salt) crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key) return Sessions.new(tid, user.id, user.role, user.password_change_needed, crypto_prv_key)