Making a distinction between users/login and admin/login with a custom authorisation backend

Hello all,

My question is basically can I see in my custom authorisation backend where the login credentials came from?

I have a custom authorisation ‘CustomBackend’, which added an additional “check if human” question to the login process

class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, todayis=None, **kwargs):

and in settings.py

AUTHENTICATION_BACKENDS = [ 'users.backend.CustomBackend', ]

The users.urls.py

urlpatterns = [
    path('login/', views.myloginview.as_view(), name='login'),
    path('logout/', views.mylogoutview.as_view(), name='logout'), 
]

and the project urls.py have

urlpatterns = [
    path('users/', include('users.urls')),
    path('admin/', admin.site.urls),
]

The user login part works great, you can login with username, password and the question code.

However the is_staf user can also login using the same user login route.
After that the is_staf is logged in, the is_staf user can go to the admin/ url and he/she is in the administration part of the website.

I don’t want that, I want users to login through users/login and is_staf users to login through admin/login

Because both routes use the same custom backend my question is can I see where the credentials came from?

What I’m aiming for in pseudo code

def authenticate( ....... ):
    if( origin_url == users/login && user == is_staf ):
        access denied.
    if( origin_url == admin/login && user != is_staf ):
        access denied.

Could someone point me in the right direction as I have no clue where I should start looking.
Thanks.

Django Version: 3.1.5
Python Version: 3.9.1

I’m not sure I understand what you’re really trying to accomplish here? What is it that you’re really trying to prevent?
The short answer is that there’s no direct way to know who generated the page that presented a form to the user that resulted in a post to a URL. You could add a hidden variable to the form, but a user can always change that, so it’s not suitable for relying upon it for security.

What I really try to prevent is that it is possible to gain is_staf privileges through the users/login url.

The users/login url is exposed to the world and in the event of a brute force attack the worst that could happen is access as a normal user.
I first tried to strip the is_staf user of the its staf privileges if logged in through the users/login and add them again if logged in through admin/login, but that seams to be very complicated and insecure :slight_smile:

Maybe it is good to mention that I have an alternate objective with the build of this website.
I try to understand Django in a short period of time and I found that the best way to do that is to try to accomplish something not standard, I choose to make my website ridiculously paranoid secure.

создайте разные группы и все!
views.py
activate
group = Group.objects.get(name=“Client”)
user.groups.add(group)

templates
group = Group.objects.get(name=“Agent”)
master = User.objects.prefetch_related(“groups”).filter(groups=group)

Thanks, had to translate

It should mean create different groups and that's it!

Could you tell me which part this solves?

  1. distinction between urls
  2. strip is_staf privileges when loggen in through users/login

Thank you

Оно все решает! С данным представлением можно вывести и различные URL, к группам прилагаются различные права!
Вы сделаете (аутентификация по токену с подтверждением по mail) и вариантов много
самый простой
{% for group in request.user.groups.all %}
{% if ‘Name’ == group.name %}

OK, I’ll work with this and try to find how it all work together.

скинь почту… вышлю простое решение

Ok, leaving aside the question as to whether or not you’re actually improving security or preventing anything substantial by doing this (which I seriously doubt), the easiest way to do this is on the beginning of this process - at the login-page itself. I would create the two login pages, each pointing to a different view. I would then check in those views whether or not the username supplied is eligible to log in using that login page.

1 Like

так оно и есть. за регистрацию и активацию = отвечает (отдельное приложение) оно и формирует (ранжир) регистрированных пользователей - по правам групп.
(этому в обед будет 100 лет)
def activate(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
group = Group.objects.get(name=“Client”)
user.groups.add(group)
У нас сегодня Старый Новый год 2021: традиции, приметы, обряды и гадания | Joy-Pup - всё самое интересное! | Яндекс Дзен
С новым годом!

To answer my own question: I found what I was looking for, in my

class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, todayis=None, **kwargs):

The authenticate function will pass the request variable.
Both
request.path
and
request.META['HTTP_REFERER']
will give me the information I need. That is in my ‘runserver’ test environment, need to test if it still works on the production server.

@KenWhitesell I know it may not be the holy grail in security but I learned something today, so my second objective is satisfied :innocent: :rofl:

Thank you both for your help and insight.

Not only is this not the holy grail, but it’s not even secure.

request.META comes from the HTTP request headers, which are set by the browser. Since it’s coming from the browser, the person submitting the form can set that to whatever they want. And if someone wants to hack your site, they’re certainly going to know how to change these headers.

So no, you’re not doing anything by interrogating these fields.

Okay, point well taken. I’ll focus my efforts on something else.
Thanks for your effort to point this out to me, it helps me to understand the content of the request variable in general and where the information came from.