def validate_app(self, existing_errors=None): errors = existing_errors or [] errors.extend(self._check_password_charset()) errors.extend(self._validate_fixtures()) errors.extend(self._validate_intents()) errors.extend(self._validate_practice_users()) try: if not errors: self.app.create_all_files() except CaseXPathValidationError as cve: errors.append({ 'type': 'invalid case xpath reference', 'module': cve.module, 'form': cve.form, }) except UserCaseXPathValidationError as ucve: errors.append({ 'type': 'invalid user property xpath reference', 'module': ucve.module, 'form': ucve.form, }) except (AppEditingError, XFormValidationError, XFormException, PermissionDenied, SuiteValidationError) as e: errors.append({'type': 'error', 'message': six.text_type(e)}) except Exception as e: if settings.DEBUG: raise # this is much less useful/actionable without a URL # so make sure to include the request notify_exception(view_utils.get_request(), "Unexpected error building app") errors.append({'type': 'error', 'message': 'unexpected error: %s' % e}) return errors
def get_raw_password(obfuscated_password, username=None): client = get_redis_client() def replay_attack(): # Replay attack where the same obfuscated password used from previous login attempt key_name = obfuscated_password_redis_key_for_user( username, obfuscated_password) if client.get(key_name): return True def record_login_attempt(): key_name = obfuscated_password_redis_key_for_user( username, obfuscated_password) client.set(key_name, True) client.expire(key_name, timedelta(days=EXPIRE_LOGIN_ATTEMPTS_IN)) def _mobile_request_to_track(username): # To be added just for audit test and should be removed to implement for all users if username not in USERS_TO_TRACK_FOR_REPLAY_ATTACK: return False return resolve(request.path ).url_name in MOBILE_REQUESTS_TO_TRACK_FOR_REPLAY_ATTACK def _decode_password(): raw_password = extract_password(obfuscated_password) if raw_password is None: # if there was no obfuscation done, just return the raw password # and skip any further checks return obfuscated_password # In case of 2-step authentication for web skip by checking for auth-username which is # present in first step if username and ((request and request.POST.get('auth-username')) or _mobile_request_to_track(username)): if replay_attack(): return '' record_login_attempt() return raw_password if settings.OBFUSCATE_PASSWORD_FOR_NIC_COMPLIANCE: request = get_request() if request: # 1. an attempt to decode a password should be done just once in a request for the login attempt # check to work correctly and not consider it a replay attack in case of multiple calls # 2. also there should be no need to decode a password multiple times in the same request. if not hasattr(request, 'decoded_password'): request.decoded_password = {} # return decoded password set on request object for the obfuscated_password if obfuscated_password in request.decoded_password: return request.decoded_password[obfuscated_password] else: # decode the password and save it on the request object for obfuscated_password request.decoded_password[ obfuscated_password] = _decode_password() return request.decoded_password[obfuscated_password] else: return _decode_password() else: return obfuscated_password
def filter(self, record): request = get_request() if request is not None: record.domain = getattr(request, 'domain', '') record.username = request.couch_user.username if getattr(request, 'couch_user', None) else '' record.hq_url = request.path else: record.domain = record.username = record.hq_url = None return True
def get_raw_password(obfuscated_password, username=None): client = get_redis_client() def replay_attack(): # Replay attack where the same obfuscated password used from previous login attempt key_name = obfuscated_password_redis_key_for_user(username, obfuscated_password) if client.get(key_name): return True def record_login_attempt(): key_name = obfuscated_password_redis_key_for_user(username, obfuscated_password) client.set(key_name, True) client.expire(key_name, timedelta(days=EXPIRE_LOGIN_ATTEMPTS_IN)) def _mobile_request_to_track(username): # To be added just for audit test and should be removed to implement for all users if username not in USERS_TO_TRACK_FOR_REPLAY_ATTACK: return False return resolve(request.path).url_name in MOBILE_REQUESTS_TO_TRACK_FOR_REPLAY_ATTACK def _decode_password(): raw_password = extract_password(obfuscated_password) if raw_password is None: # if there was no obfuscation done, just return the raw password # and skip any further checks return obfuscated_password # In case of 2-step authentication for web skip by checking for auth-username which is # present in first step if username and ( (request and request.POST.get('auth-username')) or _mobile_request_to_track(username)): if replay_attack(): return '' record_login_attempt() return raw_password if settings.OBFUSCATE_PASSWORD_FOR_NIC_COMPLIANCE: request = get_request() if request: # 1. an attempt to decode a password should be done just once in a request for the login attempt # check to work correctly and not consider it a replay attack in case of multiple calls # 2. also there should be no need to decode a password multiple times in the same request. if not hasattr(request, 'decoded_password'): request.decoded_password = {} # return decoded password set on request object for the obfuscated_password if obfuscated_password in request.decoded_password: return request.decoded_password[obfuscated_password] else: # decode the password and save it on the request object for obfuscated_password request.decoded_password[obfuscated_password] = _decode_password() return request.decoded_password[obfuscated_password] else: return _decode_password() else: return obfuscated_password
def _get_migration_status_from_threadlocals(): _default = MigrationStatus.NOT_STARTED _assert = soft_assert(['droberts' + '@' + 'dimagi.com']) try: request = get_request() try: domain = request.domain except AttributeError: return _default return get_tz_migration_status(domain) except Exception as e: _assert(False, 'Error in _get_migration_status', e) return _default
def format_angular_error(error_msg, log_error): """Gets the standard angular async error response. :param error_msg: A string that is the error message you'd like to return :param additional_data: a dictionary of additional data you'd like to pass :return: { 'error': <error_msg>, <...additional_data...>, } """ resp = {'error': error_msg} if log_error: notify_exception(get_request(), error_msg) return resp
def get_raw_password(obfuscated_password, username=None): def replay_attack(): # Replay attack where the same obfuscated password used from previous login attempt obfuscated_passwords = get_obfuscated_passwords(username) for submitted_obfuscated_password in obfuscated_passwords: if verify_password(obfuscated_password, submitted_obfuscated_password): return True def record_login_attempt(): client = get_redis_client() key_name = obfuscated_passwords_redis_key_for_user(username) obfuscated_passwords = client.get(key_name, []) client.set(key_name, obfuscated_passwords + [hash_password(obfuscated_password)]) client.expire(key_name, timedelta(EXPIRE_LOGIN_ATTEMPTS_IN)) def _decode_password(): # force check for replay attack and recording login attempt only for web sign in by checking for username # Also skip those two checks in case of 2-step authentication by checking for auth-username which is not # present in consecutive token step's POST params if username and request and request.POST.get('auth-username'): if replay_attack(): return '' record_login_attempt() return extract_password(obfuscated_password) if settings.OBFUSCATE_PASSWORD_FOR_NIC_COMPLIANCE: request = get_request() if request: # 1. an attempt to decode a password should be done just once in a request for the login attempt # check to work correctly and not consider it a replay attack in case of multiple calls # 2. also there should be no need to decode a password multiple times in the same request. if not hasattr(request, 'decoded_password'): request.decoded_password = {} # return decoded password set on request object for the obfuscated_password if obfuscated_password in request.decoded_password: return request.decoded_password[obfuscated_password] else: # decode the password and save it on the request object for obfuscated_password request.decoded_password[ obfuscated_password] = _decode_password() return request.decoded_password[obfuscated_password] else: return _decode_password() else: return obfuscated_password
def get_timezone_data_migration_complete(): """ The timezone data migration happening some time in Apr-May 2015 will shift all phone times (form.timeEnd, case.modified_on, etc.) to UTC so functions that deal with converting to or from phone times use this function to decide what type of timezone conversion is necessary """ _default = False _assert = soft_assert(['droberts' + '@' + 'dimagi.com']) try: request = get_request() try: domain = request.domain except AttributeError: return _default return USE_NEW_TIMEZONE_BEHAVIOR.enabled(domain) except Exception: _assert(False, 'Error in get_timezone_data_migration_complete') return _default
def validate_app(self, existing_errors=None): errors = existing_errors or [] errors.extend(self._check_password_charset()) errors.extend(self._validate_fixtures()) errors.extend(self._validate_intents()) errors.extend(self._validate_practice_users()) try: if not errors: self.app.create_all_files() except CaseXPathValidationError as cve: errors.append({ 'type': 'invalid case xpath reference', 'module': cve.module, 'form': cve.form, }) except UserCaseXPathValidationError as ucve: errors.append({ 'type': 'invalid user property xpath reference', 'module': ucve.module, 'form': ucve.form, }) except (AppEditingError, XFormValidationError, XFormException, PermissionDenied, SuiteValidationError) as e: errors.append({'type': 'error', 'message': six.text_type(e)}) except Exception as e: if settings.DEBUG: raise # this is much less useful/actionable without a URL # so make sure to include the request notify_exception(view_utils.get_request(), "Unexpected error building app") errors.append({ 'type': 'error', 'message': 'unexpected error: %s' % e }) return errors