Тестирование ошибка 403

I have a Test Class, that test the access of all page with different user.

Those access are defined by decorator on each of my views.

views.py :

@login_required
def afficher(request):
    ...
    ...

@creation_permission_required
def ajouter(request):
    ...
    ...

Some of these decorator are defined by me.

decorators.py :

def creation_permission_required(function):
    @wraps(function)
    @login_required
    def decorateur(request, *k, **a):
        user = get_object_or_404(User, username__iexact=request.user.username)
        if user.is_superuser or user.get_profile().creation:
            return function(request, *k, **a)
        else:
            return HttpResponseRedirect(reverse("non_autorise"))# <--- PROBLEM
    return decorateur
    return function

When I test them, I use the status_code attribute to verify if the user can access or not the page

test.py :

c = Client()
c.login(username='aucun', password='aucun')
for url in self.url_aucun:
    r = c.get(reverse(url['url'], args=url['args']))
    self.assertEqual(r.status_code, 200)
for url in self.url_creation:
    r = c.get(reverse(url['url'], args=url['args']))
    self.assertEqual(r.status_code, 302)      # <--- SECOND PROBLEM 

When a user doesn’t have the right to access a page, the page should return a 403 error (forbidden). How can I do to test 403 instead of 302 ?

EDIT : I tried to use HttpResponseForbidden(reverse(«non_autorise»)), but couldn’t get any content. So then I tried to make my own HttpResponse which is an exact copy of HttpResponseRedirect but with another status_code (403) still didn’t get any content…

decorators.py :

class HttpResponseTest(HttpResponse):
    def __init__(self, redirect_to):
        super(HttpResponseTest, self).__init__()
        self['Location'] = iri_to_uri(redirect_to)
        self.status_code = 403

def creation_permission_required(function):
    @wraps(function)
    @login_required
    def decorateur(request, *k, **a):
        user = get_object_or_404(User, username__iexact=request.user.username)
        if user.is_superuser or user.get_profile().creation:
            return function(request, *k, **a)
        else:
            return HttpResponseTest(reverse("non_autorise"))# <--- PROBLEM
    return decorateur
    return function

Время на прочтение
2 мин

Количество просмотров 6.7K

Привет, Хабр! Работая над библиотекой-обёрткой REST API, я столкнулся с проблемой. Для тестирования обработки ошибочных кодов ответа сервера (400, 500, 403 и т.д.) необходимо искусственно создавать условия на сервере для получения соответствующих кодов. При правильно настроенном сервере, например, непросто получить ошибку 500. А тестировать функции-обработчики ошибок как-то надо. Я написал небольшое API, которое генерирует ошибочные ответы сервера — httpme.tk

Как применять в тестировании?

Например, есть такой код (python3):

from requests import session as requests_session

session = requests_session()
session.hooks = {
    'response': lambda r, *args, **kwargs: raise AccessError('Доступ закрыт, т.к. сервер подключен к другой БД') if r.status_code == 403  else pass
}

class AccessError(Exception):
    """ 'своя' ошибка """
    pass

def getter(url):
    return session.get(url)

Если кратко — в коде есть функция, которая возвращает ответ сервера на GET-запрос на заданный URL, если в результате выполнения запроса возникает ошибка 403 — вызывается внутреннее исключение модуля AccessError.

Этот код надо протестировать и отладить. Cоздать вручную условия для ошибки 403, а уж тем более, например, 500 (сервер слишком хорошо работает) довольно непросто. Тестировщику не важно, при каких условиях сервер выдаст ошибку 403: он тестирует не само API (например), а функцию, которая к нему обращается. Поэтому для тестирования вызова исключения при коде статуса 403 он может сделать вот так (python3 + pytest):

import pytest
from mymodule import 

def test_forbidden():
    with pytest.raises(AccessError):
        getter('http://httpme.tk/403')

Как пользоваться?

Очень просто. Отправьте на сервер GET-запрос в формате http://httpme.tk/<status_code>. Например так (cURL):

curl -G http://httpme.tk/500

Или так (python3):

from requests import get

get('http://httpme.tk/408')  # <Response [408]>

А что внутри?

А внутри маленькое Flask-приложение, вызывающее функцию abort(status_code) на каждый запрос.

→ Ссылка на GitHub

На этом всё!

Интересно услышать оценку полезности данного сервиса сообществом.

#django #unit-testing #view #django-testing #django-tests

Вопрос:

Я действительно надеюсь, что вы можете пролить свет на загадочную ситуацию, в которой я нахожусь с моим модульным тестированием моих представлений сообщений. Я в основном пытаюсь протестировать различные разрешения на публикацию в зависимости от пользователя, например:

  1. гость (анонимный),
  2. участник (зарегистрированный), и
  3. участники, которые взаимно следят друг за другом (друзья)

Когда я запускаю модульный тест, в функции появляется ошибка, которая проверяет, может ли участник (зарегистрированный пользователь) просматривать сообщение, которое должно быть видно только друзьям (взаимно следующим друг за другом).:

 ======================================================================
ERROR: test_member_user_post_detail_friends_permission (journal.tests.test_views.TestPostDetailView)
----------------------------------------------------------------------

 

Когда я следую за строкой, в которой произошло исключение, это приводит меня к моему get_object() PostDetailView классу, где тестирование, похоже, заканчивается преждевременно (строка отмечена ниже).:

     def get_object(self, queryset=None):
        obj = super(PostDetailView, self).get_object(queryset=queryset)

        # Logged in user's friends ids (Users who they are following)
        my_friends = Follower.objects.filter(user_id=self.request.user.id).values(
            "follow_to"
        )

        # Post owner's friends id (Users who the post owner is following)
        their_friends = Follower.objects.filter(user_id=obj.user.id).values("follow_to")

        if obj.permission == "friend":  # viewable only by friends or staff/moderators

            if self.request.user.is_authenticated:
                if self.request.user.is_staff or self.request.user.is_moderator:
                    return obj

                if self.request.user.id == obj.user.id:
                    return obj

                # Check if they are following each other
                if self.request.user.id in [
                    i["follow_to"] for i in their_friends
                ] and obj.user.id in [i["follow_to"] for i in my_friends]:
                    return obj
                else:
                    raise PermissionDenied <-------------------------------------------------Issue here

        if self.request.user.is_anonymous and obj.permission != "public":
            raise PermissionDenied
        return obj
 

Ожидание:

self.assertEqual(response.status_code, 403) должен быть истинным, 403 == 403

Вопрос:

  1. Теперь я не понимаю, почему мое self.assertEqual(response.status_code, 403) утверждение не возвращает True, потому что не должно поднимать PermissionDenied == 403 ?
  2. Почему он преждевременно завершается еще до того, как мой модульный тест сможет запустить строку self.assertEqual?
  3. Как я могу изменить свой код, чтобы мой модульный тест работал успешно?

Правка: Глупый я, кажется, забыл вставить фактический тест:

     def test_member_user_post_detail_friends_permission(self):
        """
        Test if logged in user can view friend permission posts
        """
        request = self.factory.get("/journal/post/3/")
        middleware = SessionMiddleware()
        middleware.process_request(request)
        request.session.save()
        request.user = self.user_1
        response = PostDetailView.as_view()(request, pk=self.friends_post.id)
        self.assertEqual(response.status_code, 403)
 

Edit2: Это работает, если я использую client (), но не если я использую factory(). Что это дает?

         self.client.login(username="user_1", password="123456")
        response = self.client.get('/journal/post/3/')
        self.assertEqual(response.status_code, 403)
 

Комментарии:

1. PostDetailView.as_view()(request, pk=self.friends_post.id) вы напрямую передаете запрос в представление, чего вы ожидаете? Обычно существует некоторый код, который Django должен перехватывать эти исключения, а затем возвращать соответствующий ответ вместо того, чтобы вы пытались напрямую использовать представление.

В зависимости от задач можно по-разному переопределить в Django стандартное поведение на реакцию ошибок, таких как 403, 404, 500 и стандартные шаблоны вывода ошибок. В официальной документации (на рус. яз. — http://djbook.ru/rel1.8/topics/http/views.html) хорошо это описывается, но тем не менее есть некоторые нюансы, о которых я хочу рассказать и показать в примерах.

В большинстве случаев можно оставить стандартное поведение Django, т. е. стандартные views (из django.views.defaults), обрабатывающие ошибки и переопределить только шаблоны.

Допустим, у нас есть шаблон ошибки 404:

# 404.html
{% extends "base.html" %}

{% block subtitle %}Страница не найдена{% endblock %}
{% block meta %}<meta name="robots" content="noindex, nofollow">{% endblock %}

{% block content %}
    <h2>Запрашиваемая страница не найдена</h2>
    <p>Возможно, неправильно указан путь в адресной строке или страница была удалена.</p>
    <p>Возврат на <a href="/">главную страницу</a></p>
{% endblock %}

А ниже описаны разные способы переопределения.

Добавление своего шаблона в templates

Самый простой способ переопределения — это добавить этот шаблон в «my_project / templates». Именно здесь django будет искать шаблон 404.html и при наличии отрендерит.

Добавление своего шаблона в другую папку

Не всегда удобно держать шаблоны ошибок в «my_project / templates» вместе с какими-то другими шаблонами и хочется их вынести в отдельную папку. Я, к примеру, использую следующую структуру папки templates в корне проекта (жирным выделены папки):

  • admin — содержит переопределяемые админские шаблонов
  • cms — содержит переопределяемые шаблоны Django CMS
  • errs — содержит шаблоны ошибок
    • 403.html
    • 404.html
    • 500.html
  • vers — содержит проверочные файлы для поисковых систем
  • base.html
  • one_col.html
  • two_col.html
  • main.html

Как видите, вынос шаблонов ошибок в отдельную папку — хорошая идея отделить их от шаблонов страниц (one_col.html, two_col.html, main.html). Чтобы указать django, где искать шаблоны по новому пути, нужно использовать метод curry, например:

# urls.py
from django.views.defaults import server_error, page_not_found, permission_denied

handler403 = curry(permission_denied, template_name='errs/403.html')
handler404 = curry(page_not_found, template_name='errs/404.html')
handler500 = curry(server_error, template_name='errs/500.html')

Замечание: в Django>=1.9 нужно добавить ещё один аргумент exception для handler403 и handler404:

handler403 = curry(permission_denied, exception=Exception('Permission Denied'), template_name='errs/403.html')
handler404 = curry(page_not_found, exception=Exception('Page not Found'), template_name='errs/404.html')

Тестирование своих шаблонов ошибок

Чтобы протестировать шаблоны ошибок, достаточно добавить соответствующие urls в urls.py, например так:

if settings.DEBUG:
    urlpatterns = [
        url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
        url(r'', include('django.contrib.staticfiles.urls')),

        # --- error pages ---
        url(r'^403$', handler403),
        url(r'^404$', handler404),
        url(r'^500$', handler500),
    ] + urlpatterns

Теперь можно переходить по адресу http://localhost:8000/404 и видеть свой кастомный шаблон ошибки. На боевом сайте нам тестовые урлы ошибок не нужны, поэтому мы добавили их в условие if settings.DEBUG:.

Создание своего представления для обработки ошибки

Если хочется изменить стандартное поведение обработки ошибок, то нужно писать своё представление. Например:

# urls.py
handler403 = 'my_app.views.show_403'
handler404 = 'my_app.views.show_404'

# my_app/views.py
# Обработка ошибки 403
from django.core.exceptions import PermissionDenied
def show_403(request):
    # какие-либо действия
    raise PermissionDenied

# Обработка ошибки 404
from django.http.response import Http404
def show_404(request):
    # какие-либо действия
    raise Http404

Можно усложнить пример с обработкой ошибки 404. Например, мы хотим отдавать разные шаблоны 404 в зависимости от того, с чего начинается отсутствующий url:

# Обработка ошибки 404
from django.http.response import Http404
def 404(request):
    if request.path.startswith('/project/'):
        return render(request, 'project_not_found.html')  # выдаст страницу, что проекта нет и, к примеру, покажет другие проекты
    if request.path.startswith('/shop/'):
        return render(request, 'product_not_found.html')  # выдаст страницу, что товара нет и, к примеру, покажет другие товары

    raise Http404  # в остальных случаях показать стандартное исключение, которое отрендерит наш шаблон 404.html

Некоторые тонкости

Проверка отдачи шаблона 404

Для проверки отдачи шаблона 404 используйте при значении переменной DEBUG=False в settings.py, иначе вам будет показан трейсбек Django.

Внимание! Если DEBUG=False, то вы должны добавить в ALLOWED_HOSTSsettings.py) допустимые доменные имена, иначе Django будет выдавать ошибку “Bad Request (400)”. На локальной машине добавляется ‘localhost’ (или 127.0.0.1).

# settings.py
ALLOWED_HOSTS = ['localhost', ]

Обратите внимание, что при DEBUG=False статические файлы не будут показываться. Для показа статических файлов нужно собрать статику и запустить сервер с опцией --insecure:

python manage.py collectstatic
python manage.py runserver --insecure

Создание своего представления для обработки 500 ошибки

При использовании стандартного представления обработки 500 ошибки в соответствующий шаблон не передаётся контекст. Сделано так для того, чтобы уменьшить количество возможных других ошибок. Поэтому шаблон должен быть простой подобный этому:

<!DOCTYPE html>
<html>
<head>
    <title>Ошибка на стороне сервера</title>
    <meta name="robots" content="noindex, nofollow">
</head>
<body>
    <p>Извините, но что-то случилось с сайтом.</p>
    <p>В техническую поддержку уже отправлено уведомление.</p>
</body>
</html>

Если будете делать своё представление для 500 ошибки, то следуйте правилам django — не передавайте RequestContext при рендеринге шаблона. Посмотрите как происходит обработка в стандартном представлении django.views.defaults.server_error.

Отображение ошибок без рендеринга шаблонов

from django.http import HttpResponseNotFound 

def test_view_1(request, param):  
  if not param:  # какое-то условие
    return HttpResponseNotFound('<p>Страница не найдена</p>')  

  return render_to_response('test_view_1.html')  


from django.http.response import HttpResponseForbidden
def test_view_2(request, param):
    if not param:
        return HttpResponseForbidden('Доступ запрещён')

    return render_to_response('test_view_2.html')

Надеюсь, статья помогла ответить на возникающие вопросы об обработке ошибок в Django.

Оцените статью

3.9 из 5 (всего 7 оценок)

После нажатия кнопки «Отправить» ваше сообщение будет доставлено мне на почту.

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/django-custom-templates-for-errors/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/django-custom-templates-for-errors/">https://vivazzi.pro/ru/it/django-custom-templates-for-errors/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.

Table of Contents

  • Introduction: What is a 403 Error?
  • 1. Firewall Rules
    – 403 on an Image or File
  • 2. Caching and Nonces
  • 3. File Permissions
  • 4. CDN Issues
  • 5. Corrupt/Misconfigured .htaccess file
  • 6. Missing WordPress Core Files
  • 7. Broken/Missing Plugins
  • 8. Custom Nginx Config Rules

Introduction: What is a 403 Forbidden Error?

The 403 Forbidden error occurs when a request is made the server cannot allow. This is often due to a firewall ruleset that strictly prohibits this specific request, but other settings such as permissions may prevent access based on user rights.

When 403s occur, your server understands the request that is being made, but is refusing to comply with the request. 

That’s about all there is to it. Your request is forbidden.

Error Messaging

On Nginx a 403 looks as follows: 403 Forbidden – nginx

Other variations of a 403 include:

  • 403 – Forbidden: Access is denied
  • Error 403 – Forbidden
  • 403 – Forbidden Error – You are not allowed to access this address
  • HTTP Error 403 – Forbidden – You do not have permission to access the document or program you requested
  • 403 Forbidden – Access to this resource on the server is denied


Note

The following are all certainly possibilities for your 403 errors, however, in 90% of cases, 403 errors are caused by a firewall, caching issue, or permissions issue.

Connecting to Your Servers

Some of the following may require you to SSH into your server. Don’t worry, almost anything you may need to do via SSH by following articles here in our knowledge base is the equivalent of basic HTML difficulty-wise. Please see these guides to get started:

1. Firewall Rules

By far the most common reason for 403 errors is that the request you’re making is being blocked for breaking one of the firewall rules.

Unlike most other hosting providers, GridPane equips you with 1-3 different Web Application Firewall (WAF) options depending on your plan: –

  1. 6G WAF
  2. 7G WAF
  3. ModSecurity

Usually, 403s are a good thing. In most cases, these types of requests are malicious in nature and the firewall blocks those from even reaching your application (WordPress website). However, WordPress is a vast ecosystem of different functionality and false positives can and do occur.

The quickest way to discover if your 403 error is being caused by a WAF is to simply turn it off and try to reproduce the issue. If the 403 no longer occurs, this is a WAF issue.

You can find out the specific reason the request is being blocked by checking the log. This is available directly inside the security tab at the bottom of the settings.

Once you know the cause, you can begin crafting an exclusion that is fairly straightforward, and fully documented in the links above.

Example

Here’s an example of a request that resulted in a 403 error with the 7G WAF:

website.com/wp-admin/admin.php?page=seopress-google-analytics&code=4/0AY0eSoaWlA&scope=https://www.googleapis.com/auth/analytics.readonly

This request broke 2 rules, as detailed by this result in the 7G WAF log:

[17/Nov/2020:15:05:35 +0000] [":bad_querystring_12::bad_request_15:"] 199.199.199.199 yourdomain.com "GET /wp-admin/admin.php?page=seopress-google-analytics&code=4/0AY0e-g44ZrE9024kffJQ2LbRdRxVLOQgAruyU9wAHI1jYFCDaUo10xmwW5rpilPzqNKOSoaWlA&scope=https://www.googleapis.com/auth/analytics.readonly HTTP/1.1" 403 "https://accounts.google.com/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36"

Using this information we can create a rule to exclude these two results by targeting “page=seopress-google-analytics&code” and adding an exclusion for both errors like so:

set $exclusion_rule_match "";
if ( $args ~* ^page=seopress-google-analytics&code ) {
set $exclusion_rule_match 15;
}
if ($bad_request_7g = $exclusion_rule_match) {
set $7g_drop_bad_request 0;
}
set $exclusion_rule_match "";
if ( $args ~* ^page=seopress-google-analytics&code ) {
set $exclusion_rule_match 12;
}
if ($bad_querystring_7g = $exclusion_rule_match) {
set $7g_drop_bad_query_string 0;
}

Please see the full articles for a complete tutorial.

403 on an Image or File

Following on from the above section, images or files may sometimes return a 403 for a seemingly unknown reason.

These can be difficult to troubleshoot because it’s really not obvious what the cause is, however, this is almost certainly

A couple of examples to illustrate this are images/files that contain either the word “Specialist” or the word “Conference”. 

The reason these get flagged are due to the word conference containing “conf” (which is a file name extension), and specialist containing the name of a commonly spammed pharmaceutical.

The quickest solution is to rename the file, or to edit out that specific line or word in the firewall. Our documentation has details how to do this here:

Using the GridPane 7G Web Application Firewall

2. Caching and Nonces

The second most common issue outside of a firewall rule being is broken is where caching is interfering with a form (such as a contact form, or payment gateway form). Here, the form uses what’s called a “nonce” (a security token which is a number or random string used only once), which exists for a set period of time (12 hours is common) after which it changes to something new. Once change occurs, the cache may serve the outdated nonce and this results in an error.

If you have a form or any functionality that makes use of a nonce, these can break and return 403 errors if the cache isn’t cleared once the nonce expires.

In many cases, nonces last 12-24 hours. For example, the Gravity forms payment gateway has a 12-hour nonce and can result in 403 errors if cached for over 12 hours.

If clearing the cache allows your functionality to begin operating correctly again, this is a caching issue.

Plugins we know of that may experience cache related issues are:

  1. Gravity Forms Payments
  2. Divi Forms
  3. Caldera Forms

In these cases, there are a couple of different solutions.

Solution 1. Exclude the page from the cache

If you exclude the page from the cache, the cache will not interfere with the nonce and all forms will operate as normal. 

Please see the following guide on how to exclude a page from your website’s cache (Nginx only):

Exclude a page from server caching

Solution 2. Reduce Cache TTL

If you’re using Redis Page Caching, the default TTL is 30 days. If you’re experiencing nonce related form failures, you can reduce the cache time to avoid these in the future.

This requires running a single GP-CLI command. To do so, you will need to SSH into your server. Please see the following guides to get started:

The command for altering the default caching TTL is as follows:

gp stack nginx redis -site-cache-valid {accepted.value} {site.url}

Run the following command to reduce cache time to 6 hours (replacing site.url with your domain name):

gp stack nginx redis -site-cache-valid 21600 site.url

The time length has to be entered in seconds. In this case, 6 hours = 21600 seconds.

For 10 hours, run the following:

gp stack nginx redis -site-cache-valid 36000 site.url

For more details, please see this Redis Page caching section in the Configure Nginx article:

Set caching expiry time for all successful requests going into Redis SRCache page cache

3. Permissions

403 errors can also be caused by incorrect permissions settings. This can sometimes occur when migrating a website over to GridPane.

Fortunately, we have a quick fix self-help tool that can help reset your website to the correct permissions very quickly and with minimal fuss. To fix your websites permissions, please see this article:

Self Help Tools: Reset Application File Permissions

4. CDN Issues

If the 403 forbidden errors you’re experiencing are specific to your assets (images, CSS, and JS files), and you’re using a delivery network (CDN) for your website, try temporarily disabling this service to see if this is at the root of your issue.

If it isn’t, this is likely firewall related, possibly due to 7G Bad Bot rule #5.

5. Corrupt/Misconfigured .htaccess File

Nginx doesn’t use .htaccess, so this error is OpenLiteSpeed specific for GridPane hosted websites.

This is a very powerful file, and if corrupted or misconfigured, this could result in a 403 error for your website.

Fortunately, GridPane keeps a backup copy that you can use in the case of an emergency:

You can get your website back up and running by replacing the current .htaccess file with the contents of the .htaccess.save file.

This is easier done over SFTP. To connect to your server over SFTP, please see either one of the following articles:

Connect to a GridPane Server by SFTP as System User

Connect to a GridPane Server by SFTP as Root user

Step 1

Once connected, first save a copy of the .htaccess.save file to your computer.

Step 2

Next, rename the corrupt .htaccess file to .htaccess.bad

Step 3

Next, rename .htaccess.save to .htaccess and then check your website.

Step 4

You can now re-upload the .htaccess.save to your server again for safekeeping, and delete the .htaccess.bad file.

6. Missing WordPress Core Files

If there are missing Core WordPress files on your site, or if one has been moved to another directory for some reason (I can recall one case where a client had decided to move their wp-settings.php file outside of htdocs, then created an emergency support ticket without any details of what they’d just done).

This may result in either a 403 or a 500 error. The previous section above contains a list of the files inside htdocs – note that those that begin with a “.” are hidden files.

You can run a check with the following command (replace site.url with your domain name):

gp wp site.url core verify-checksums

For example:

gp wp yourwebsite.com core verify-checksums

This will check your core WordPress installation files and let you know if any issues need to be addressed. 

This type of issue is usually the result of malware.

7. Broken/Missing Theme or Plugin Files

If none of the above is the cause for your 403 error, then this could be the work of a broken or missing plugin file.

To check, connect to your server over SFTP (see the links in part 5 above to get started) and rename the plugins folder (located at site.url/htdocs/wp-content/plugins) to plugins-off.

Next, check your website and see if the 403 error is occurring. If not, then you know the root cause is one of the plugins on your website.

Rename the plugins-off directory back to plugins, and then do the same for each of your individual plugin folders, renaming them one by one until you find the one responsible.

8. Custom Nginx Configurations

Sometimes plugin authors can be rather careless with their Nginx recommendations, documenting broad Nginx rules that can result in unexpected/undesirable behavior such as blocking specific types of files altogether, or blocking them when not logged into the website.

You may have added custom configuration rules to Nginx via .conf files in your  /var/www/site.url/nginx directory.

For example:

/var/www/example.com/nginx/ithemes-security-main-context.conf

Custom configurations that affect ALL websites on the server may also have been added in these directories:

/etc/nginx/extra.d/
/etc/nginx/conf.d/

Be sure to check this directory for any Nginx configuration files that you or your team members may have added (be sure to ask them so you know what to look for), and review them for code that could prevent access to page or file that your getting your 403 forbidden error.

There is Django app and a test for it. I am receiving the error:

Traceback (most recent call last):
  File "../support/tests.py", line 17, in foo
    self.assertEqual(response.status_code, HttpResponseForbidden.status_code)
AssertionError: 200 != 403

The code for the test itself, that causes trouble is:

response = self.client.get('/support/download/bar/')
self.assertEqual(response.status_code, HttpResponseForbidden.status_code)

I don’t understand the routine to diagnose this problem, where to start looking at. Browsing web for similar issue didn’t help.

Looks like there is some problem with the url /support/download/bar/?

Jongware's user avatar

Jongware

22.1k8 gold badges52 silver badges100 bronze badges

asked Aug 1, 2014 at 6:45

0leg's user avatar

0

The test you are doing in your tests.py :

self.assertEqual(response.status_code, HttpResponseForbidden.status_code)

You are checking if the response when you go to the url /support/download/bar/ is a HttpResponseForbidden (code 403).

Apparently, you page successfully displays (code 200), which explains your error :

AssertionError: 200 != 403

You were expecting an error, but you got success displaying the webpage.

answered Aug 1, 2014 at 6:52

Raphael Laurent's user avatar

Raphael LaurentRaphael Laurent

1,9411 gold badge16 silver badges26 bronze badges

4

It looks like this test has detected an error in your application (or else the expectation of the test itself is in error). Your application is returning a 200 OK when the test expects a 403, which I can only assume indicates that some sort of access restriction or security measure is not working.

The first step to figuring out what’s going on here is to find out why the test is expecting a 403. What is supposed to be happening? Inspect the source code and especially the middleware and decorators (that’s where a lot of permissions checks happen) and inspect the test code to see if it’s set up properly.

If you really don’t understand why the test is checking for that or how that 403 error code is supposed to come about, you will have to do some investigating depending on where you got the code (assuming you did not write it yourself). Asking the people who wrote it, or inspecting the git commit message that added the test, or moving backwards in time in the git history until you find a point where the test was working, are all options.

answered Aug 1, 2014 at 6:50

Andrew Gorcester's user avatar

Andrew GorcesterAndrew Gorcester

19.5k7 gold badges57 silver badges72 bronze badges

5

У меня есть тестовый класс, который проверяет доступ всех страниц с другим пользователем.

Эти права доступа определяются декоратором на каждом из моих просмотров.

views.py:

@login_required
def afficher(request):
    ...
    ...

@creation_permission_required
def ajouter(request):
    ...
    ...

Некоторые из этих декораторов определены мной.

decorators.py:

def creation_permission_required(function):
    @wraps(function)
    @login_required
    def decorateur(request, *k, **a):
        user = get_object_or_404(User, username__iexact=request.user.username)
        if user.is_superuser or user.get_profile().creation:
            return function(request, *k, **a)
        else:
            return HttpResponseRedirect(reverse("non_autorise"))# <--- PROBLEM
    return decorateur
    return function

Когда я тестирую их, я использую атрибут status_code, чтобы проверить, может ли пользователь получить доступ к странице.

test.py:

c = Client()
c.login(username='aucun', password='aucun')
for url in self.url_aucun:
    r = c.get(reverse(url['url'], args=url['args']))
    self.assertEqual(r.status_code, 200)
for url in self.url_creation:
    r = c.get(reverse(url['url'], args=url['args']))
    self.assertEqual(r.status_code, 302)      # <--- SECOND PROBLEM 

Если пользователь не имеет права доступа к странице, страница должна вернуть ошибку 403 (запрещено). Как я могу сделать тест 403 вместо 302?

РЕДАКТИРОВАТЬ: я пытался использовать HttpResponseForbidden(reverse(«non_autorise»)), но не смог получить никакого контента. Тогда я попытался создать свой собственный HttpResponse, который является точной копией HttpResponseRedirect, но с другим status_code (403) все еще не получил никакого контента…

decorators.py:

class HttpResponseTest(HttpResponse):
    def __init__(self, redirect_to):
        super(HttpResponseTest, self).__init__()
        self['Location'] = iri_to_uri(redirect_to)
        self.status_code = 403

def creation_permission_required(function):
    @wraps(function)
    @login_required
    def decorateur(request, *k, **a):
        user = get_object_or_404(User, username__iexact=request.user.username)
        if user.is_superuser or user.get_profile().creation:
            return function(request, *k, **a)
        else:
            return HttpResponseTest(reverse("non_autorise"))# <--- PROBLEM
    return decorateur
    return function

Понравилась статья? Поделить с друзьями:
  • Тестирование оперативной памяти на наличие ошибок
  • Тестирование не выявляет наличие ошибок
  • Тестирование на ошибки программного кода
  • Тестирование машины на ошибки
  • Тестирование и исправление ошибка субд