Example #1
0
    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
Example #2
0
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
Example #3
0
 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
Example #4
0
 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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
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
Example #10
0
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
Example #11
0
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
Example #12
0
    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