def post(self): request = self.validate_message(self.request.content.read(), requests.TokenAuthDesc) tid = int(request['tid']) if tid == 0: tid = self.request.tid delay = random_login_delay() if delay: yield deferred_sleep(delay) session = Sessions.get(request['token']) if session is None or session.tid != tid: Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication connection_check(self.request.client_ip, tid, session.user_role, self.request.client_using_tor) session = Sessions.regenerate(session.id) log.debug("Login: Success (%s)" % session.user_role) if tid != self.request.tid: returnValue({ 'redirect': 'https://%s/#/login?token=%s' % (State.tenant_cache[tid].hostname, session.id) }) returnValue(session.serialize())
def test_single_session_per_whistleblower(self): """ Asserts that the first_id is dropped from Sessions and requests using that session id are rejected """ yield self.perform_full_submission_actions() handler = self.request({ 'receipt': self.dummySubmission['receipt'] }) handler.request.client_using_tor = True response = yield handler.post() first_id = response['session_id'] wbtip_handler = self.request(headers={'x-session': first_id}, handler_cls=WBTipInstance) yield wbtip_handler.get() response = yield handler.post() second_id = response['session_id'] wbtip_handler = self.request(headers={'x-session': first_id}, handler_cls=WBTipInstance) yield self.assertRaises(errors.NotAuthenticated, wbtip_handler.get) self.assertTrue(Sessions.get(first_id) is None) valid_session = Sessions.get(second_id) self.assertTrue(valid_session is not None) self.assertEqual(valid_session.user_role, 'whistleblower') wbtip_handler = self.request(headers={'x-session': second_id}, handler_cls=WBTipInstance) yield wbtip_handler.get()
def test_single_session_per_whistleblower(self): """ Asserts that the first_id is dropped from Sessions and requests using that session id are rejected """ yield self.perform_full_submission_actions() handler = self.request({'receipt': self.lastReceipt}) handler.request.client_using_tor = True response = yield handler.post() first_id = response['session_id'] wbtip_handler = self.request(headers={'x-session': first_id}, handler_cls=WBTipInstance) yield wbtip_handler.get() response = yield handler.post() second_id = response['session_id'] wbtip_handler = self.request(headers={'x-session': first_id}, handler_cls=WBTipInstance) yield self.assertRaises(errors.NotAuthenticated, wbtip_handler.get) self.assertTrue(Sessions.get(first_id) is None) valid_session = Sessions.get(second_id) self.assertTrue(valid_session is not None) self.assertEqual(valid_session.user_role, 'whistleblower') wbtip_handler = self.request(headers={'x-session': second_id}, handler_cls=WBTipInstance) yield wbtip_handler.get()
def test_single_session_per_user(self): handler = self.request({ 'tid': 1, 'username': '******', 'password': helpers.VALID_PASSWORD1 }) r1 = yield handler.post() r2 = yield handler.post() self.assertTrue(Sessions.get(r1['session_id']) is None) self.assertTrue(Sessions.get(r2['session_id']) is not None)
def test_single_session_per_user(self): handler = self.request({ 'tid': 1, 'username': '******', 'password': helpers.VALID_PASSWORD1, 'authcode': '' }) r1 = yield handler.post() r2 = yield handler.post() self.assertTrue(Sessions.get(r1['session_id']) is None) self.assertTrue(Sessions.get(r2['session_id']) is not None)
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 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 returns a session """ 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 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 if user.two_factor_enable: if authcode != '': if user.crypto_pub_key: two_factor_secret = GCE.asymmetric_decrypt( crypto_prv_key, user.two_factor_secret).decode('utf-8') else: two_factor_secret = user.two_factor_secret.decode('utf-8') # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec if not pyotp.TOTP(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)
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, crypto_prv_key)
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 Sessions.new(tid, wbtip.id, 'whistleblower', False)
def request(self, body='', uri=b'https://www.globaleaks.org/', user_id=None, role=None, multilang=False, headers=None, client_addr=None, handler_cls=None, attached_file=None, kwargs={}): """ Constructs a handler for preforming mock requests using the bag of params described below. """ from globaleaks.rest import api if handler_cls is None: handler_cls = self._handler request = forge_request(uri=uri, headers=headers, body=body, client_addr=client_addr, method=b'GET') x = api.APIResourceWrapper() x.preprocess(request) if not getattr(handler_cls, 'decorated', False): for method in ['get', 'post', 'put', 'delete']: if getattr(handler_cls, method, None) is not None: decorators.decorate_method(handler_cls, method) handler_cls.decorated = True handler = handler_cls(self.state, request, **kwargs) if multilang: request.language = None if user_id is None and role is not None: if role == 'admin': user_id = self.dummyAdminUser['id'] elif role == 'receiver': user_id = self.dummyReceiverUser_1['id'] elif role == 'custodian': user_id = self.dummyCustodianUser['id'] if headers is not None and headers.get('x-session', None) is not None: handler.request.headers[b'x-session'] = headers.get( 'x-session').encode() elif role is not None: session = Sessions.new(1, user_id, role, False, USER_PRV_KEY) handler.request.headers[b'x-session'] = session.id.encode() if handler.upload_handler: handler.uploaded_file = self.get_dummy_file( u'upload.raw', attached_file) return handler
def post(self): request = self.validate_message(self.request.content.read(), requests.TokenAuthDesc) yield login_delay(self.request.tid) self.state.tokens.use(request['token']) session = Sessions.get(request['authtoken']) if session is None or session.tid != self.request.tid: login_failure(self.request.tid, 0) connection_check(self.request.tid, self.request.client_ip, session.user_role, self.request.client_using_tor) session = Sessions.regenerate(session.id) returnValue(session.serialize())
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 get(self, tid): tid = int(tid) check = yield check_tenant_auth_switch(self.current_user, tid) if check: session = Sessions.new(tid, self.current_user.user_id, self.current_user.user_role, self.current_user.pcn, self.current_user.cc) returnValue({ 'redirect': '/t/%d/#/login?token=%s' % (tid, session.id) })
def get(self, tid): tid = int(tid) check = yield check_tenant_auth_switch(self.current_user, tid) if check: session = Sessions.new(tid, self.current_user.user_id, self.current_user.user_tid, self.current_user.user_role, self.current_user.pcn, self.current_user.cc) returnValue({ 'redirect': '/t/%d/#/login?token=%s' % (tid, session.id) })
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 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)
def login(session, tid, username, password, 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 if user is None: log.debug("Login: Invalid credentials") Settings.failed_login_attempts += 1 raise errors.InvalidAuthentication if not client_using_tor and not State.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 State.tenant_cache[tid]['ip_filter_authenticated_enable']: ip_networks = parse_csv_ip_ranges_to_ip_networks( State.tenant_cache[tid]['ip_filter_authenticated']) if isinstance(client_ip, binary_type): client_ip = client_ip.decode() 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 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)
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.key)) 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 init_state(): Settings.set_devel_mode() Settings.disable_notifications = True Settings.failed_login_attempts.clear() Settings.working_path = os.path.abspath('./working_path') Settings.eval_paths() if os.path.exists(Settings.working_path): shutil.rmtree(Settings.working_path) orm.set_thread_pool(FakeThreadPool()) State.settings.enable_api_cache = False State.tenant_cache[1] = ObjectDict() State.tenant_cache[1].hostname = 'www.globaleaks.org' State.tenant_cache[1].encryption = True State.init_environment() Sessions.clear()
def init_state(): Settings.testing = True Settings.set_devel_mode() Settings.logging = None Settings.failed_login_attempts = 0 Settings.working_path = os.path.abspath('./working_path') Settings.eval_paths() if os.path.exists(Settings.working_path): dir_util.remove_tree(Settings.working_path, 0) orm.set_thread_pool(FakeThreadPool()) State.settings.enable_api_cache = False State.tenant_cache[1] = ObjectDict() State.tenant_cache[1].hostname = 'www.globaleaks.org' State.init_environment() Sessions.clear()
def get(self, tid): check = yield check_tenant_auth_switch(self.current_user, tid) if check: session = Sessions.new(tid, self.current_user.user_id, self.current_user.user_role, self.current_user.pcn, self.current_user.cc) returnValue({ 'redirect': 'https://%s/#/login?token=%s' % (State.tenant_cache[tid].hostname, session.id) })
def get(self, tid): if self.request.tid != 1: raise errors.InvalidAuthentication tid = int(tid) session = Sessions.new(tid, self.current_user.user_id, self.current_user.user_tid, self.current_user.user_role, False, True, self.current_user.cc, self.current_user.ek, True) return {'redirect': '/t/%d/#/login?token=%s' % (tid, session.id)}
def init_state(): Settings.testing = True Settings.set_devel_mode() Settings.logging = None Settings.failed_login_attempts = 0 Settings.working_path = os.path.abspath('./working_path') Settings.eval_paths() if os.path.exists(Settings.working_path): dir_util.remove_tree(Settings.working_path, 0) orm.set_thread_pool(FakeThreadPool()) State.settings.enable_api_cache = False State.tenant_cache[1] = ObjectDict() State.tenant_cache[1].hostname = 'www.globaleaks.org' State.tenant_cache[1].encryption = True State.init_environment() Sessions.clear()
def request(self, body='', uri=b'https://www.globaleaks.org/', user_id=None, role=None, multilang=False, headers=None, client_addr=None, handler_cls=None, attached_file=None, kwargs={}): """ Constructs a handler for preforming mock requests using the bag of params described below. """ from globaleaks.rest import api if handler_cls is None: handler_cls = self._handler request = forge_request(uri=uri, headers=headers, body=body, client_addr=client_addr, method=b'GET') x = api.APIResourceWrapper() x.preprocess(request) if not getattr(handler_cls, 'decorated', False): for method in ['get', 'post', 'put', 'delete']: if getattr(handler_cls, method, None) is not None: decorators.decorate_method(handler_cls, method) handler_cls.decorated = True handler = handler_cls(self.state, request, **kwargs) if multilang: request.language = None if user_id is None and role is not None: if role == 'admin': user_id = self.dummyAdminUser['id'] elif role == 'receiver': user_id = self.dummyReceiverUser_1['id'] elif role == 'custodian': user_id = self.dummyCustodianUser['id'] if headers is not None and headers.get('x-session', None) is not None: handler.request.headers[b'x-session'] = headers.get('x-session').encode() elif role is not None: session = Sessions.new(1, user_id, role, False, USER_PRV_KEY) handler.request.headers[b'x-session'] = session.id.encode() if handler.upload_handler: handler.uploaded_file = self.get_dummy_file(u'upload.raw', attached_file) return handler
def get_current_user(self): # Check for the session header session_id = self.request.headers.get(b'x-session') if session_id is None: return session = Sessions.get(session_id.decode()) if session is not None and session.tid == self.request.tid: self.request.current_user = session if self.request.current_user.user_role != 'whistleblower' and \ self.state.tenant_cache[1].get('log_accesses_of_internal_users', False): self.request.log_ip_and_ua = True return session
def validate_password_reset(session, tid, reset_token): """Retrieves a user given a password reset validation token""" user = session.query(models.User).filter( models.User.reset_password_token == reset_token, models.User.reset_password_date >= datetime.now() - timedelta(hours=72) ).one_or_none() if user is None: return # Token is used, void it out user.reset_password_token = None user.reset_password_date = datetime_now() user.password_change_needed = True session = Sessions.new(tid, user.id, user.role, user.password_change_needed) return session.id
def validate_password_reset(session, tid, reset_token): """Retrieves a user given a password reset validation token""" user = session.query(models.User).filter( models.User.reset_password_token == reset_token, models.User.reset_password_date >= datetime.now() - timedelta(hours=72) ).one_or_none() if user is None: return # Token is used, void it out user.reset_password_token = None user.reset_password_date = datetime_now() user.password_change_needed = True session = Sessions.new(tid, user.id, user.role, user.password_change_needed, '') return session.id
def get_current_user(self): api_session = self.get_api_session() if api_session is not None: return api_session # Check for the session header session_id = self.request.headers.get(b'x-session') if session_id is None: return # Check that that provided session exists and is legit # We need to convert here to text_type as sessions generate a # random string in text form. It seems sessions assume that it will # be a string while twisted returns headers in bytes session = Sessions.get(text_type(session_id, 'utf-8')) if session is not None and session.tid == self.request.tid: return session
def get_current_user(self): api_session = self.get_api_session() if api_session is not None: return api_session # Check for the session header session_id = self.request.headers.get(b'x-session') if session_id is None: return session = Sessions.get(text_type(session_id, 'utf-8')) if session is not None and session.tid == self.request.tid: self.request.current_user = session if self.request.current_user.user_role != 'whistleblower' and \ self.state.tenant_cache[1].get(u'log_accesses_of_internal_users', False): self.request.log_ip_and_ua = True return session
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 setUp(self): yield helpers.TestHandlerWithPopulatedDB.setUp(self) session = Sessions.new(1, self.dummyReceiver_1['id'], 'receiver', False, '') self.token = session.id
def setUp(self): yield helpers.TestHandlerWithPopulatedDB.setUp(self) session = Sessions.new(1, self.dummyReceiver_1['id'], 1, 'receiver', False, False, '') self.token = session.id
def initialization(self): # we need to reset settings.session to keep each test independent Sessions.clear() # we need to reset ApiCache to keep each test independent ApiCache.invalidate()
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)
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)