Opened 16 years ago

Last modified 20 months ago

#6363 new Bug

Login page is redisplayed without any message if AdminSite.has_permission() returns False

Reported by: Michel Sabchuk Owned by:
Component: contrib.admin Version: dev
Severity: Normal Keywords:
Cc: net147 Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: yes Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I found a bug when using the has_permission method of the AdminSite class to filter which users can access the admin page:

class SuperuserAdminSite(admin.AdminSite):
    def has_permission(self, request):
        return super(SuperuserAdminSite, self).has_permission(request) and request.user.is_superuser
admin_site = SuperuserAdminSite()

When I try to log on a user that is not a superuser, it already get the login but stay on the login page (with the header but no application loaded), I think this is a bug :) The user should get a error message as if it passed a wrong password or such, isn´t it?

Attachments (3)

weirdness.png (8.7 KB ) - added by Karen Tracey <kmtracey@…> 16 years ago.
6363.diff (2.7 KB ) - added by Karen Tracey <kmtracey@…> 16 years ago.
6363-1.diff (2.7 KB ) - added by Karen Tracey <kmtracey@…> 16 years ago.
Fixed patch -- like I said this logic is more convoluted than I like

Download all attachments as: .zip

Change History (19)

comment:1 by Marc Fargas, 16 years ago

Component: UncategorizedAdmin interface
Version: SVNnewforms-admin

I assume this has to do with newforms-admin branch?
The ticket is 5 months old, could you please check if it's still valid?

comment:2 by Karen Tracey <kmtracey@…>, 16 years ago

Has patch: set
Keywords: nfa-someday added
Triage Stage: UnreviewedAccepted

I think I see the problem. If you try to create a SuperuserAdminSite that only superusers are allowed to login to, as shown by the supplied code, then when you navigate to that site and present login information for a staff (but not superuser) user and press the "Log In" button, the login page is redisplayed without any error messages, plus the user-tools links div overlays the login form (I'll attach an image).

Problem is the base AdminSite during login assumes that any user that is_staff can access the admin site. I've created a patch that fixes this. Logic is a little more convoluted than I'd like because the has_permission method takes a request object and the user logging in is only associated with the request object after login() is called, so in the case where the user is a staff member but doesn't pass the site's has_permission test you have to call login to get the user attached to the request, then has_permission to check for permissions, then logout to detach the insufficiently qualified user from the request and replace them with the AnonymousUser again.

Accepting based on the assumption that this is something one should be able to do in newforms-admin? Feel free to correct me if I'm wrong on that though. Tagging nfa-someday since I don't see it as super high-priority.

by Karen Tracey <kmtracey@…>, 16 years ago

Attachment: weirdness.png added

by Karen Tracey <kmtracey@…>, 16 years ago

Attachment: 6363.diff added

by Karen Tracey <kmtracey@…>, 16 years ago

Attachment: 6363-1.diff added

Fixed patch -- like I said this logic is more convoluted than I like

comment:3 by Ramiro Morales, 13 years ago

Needs tests: set

comment:4 by net147, 13 years ago

Cc: net147 added

comment:5 by Julien Phalip, 13 years ago

Severity: Normal
Type: Bug

comment:6 by Aymeric Augustin, 12 years ago

UI/UX: unset

Change UI/UX from NULL to False.

comment:7 by Aymeric Augustin, 12 years ago

Easy pickings: unset

Change Easy pickings from NULL to False.

comment:8 by David Gouldin, 12 years ago

Just verified that this does still happen on current trunk, though the patch is of course very outdated at this point.

comment:9 by David Gouldin, 12 years ago

It looks like the 2 problem spots now are:

https://github.com/django/django/blob/master/django/contrib/admin/views/decorators.py#L14

and

https://github.com/django/django/blob/master/django/contrib/admin/forms.py#L41

Both of these should be modified to use AdminSite.has_permission. *How* that's to be done, I don't yet have any idea. ;-)

comment:10 by Tim Graham, 11 years ago

Found a patch, looks like it needs tests:

https://github.com/django/django/pull/925

comment:11 by tanner, 9 years ago

I cannot reproduce this bug with master. can be closed IMO

comment:12 by Claude Paroz, 9 years ago

The visual quirk about user tools is gone. But there is still a small difference in that the authentication simply refuse the login and redisplay the login form without any explanation (like it would have given if user is not staff or password is wrong).

Tentative resolution:

  • django/contrib/admin/forms.py

    diff --git a/django/contrib/admin/forms.py b/django/contrib/admin/forms.py
    index 2e482b9..f40b2fc 100644
    a b class AdminAuthenticationForm(AuthenticationForm):  
    1717    required_css_class = 'required'
    1818
    1919    def confirm_login_allowed(self, user):
    20         if not user.is_active or not user.is_staff:
     20        if not self.request.admin_site.has_permission(self.request):
    2121            raise forms.ValidationError(
    2222                self.error_messages['invalid_login'],
    2323                code='invalid_login',
  • django/contrib/admin/sites.py

    diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
    index 4b5ee57..ff6767f 100644
    a b class AdminSite(object):  
    392392            'authentication_form': self.login_form or AdminAuthenticationForm,
    393393            'template_name': self.login_template or 'admin/login.html',
    394394        }
     395        request.admin_site = self
    395396        return login(request, **defaults)
    396397
    397398    @never_cache

comment:13 by Iacopo Spalletti, 9 years ago

@claudep proposed solution almost works, but request in confirm_login_allowed still does not carry the actual user, but the pre-login one (which is likely AnonymousUser).
A solution would be setting the user on request before passing to AdminSite.has_permission (eventually resetting it to the original after that).
Does it sound good?

  • django/contrib/admin/forms.py

    diff --git a/django/contrib/admin/forms.py b/django/contrib/admin/forms.py
    index 2e482b9..e1d6fef 100644
    a b class AdminAuthenticationForm(AuthenticationForm):  
    1717    required_css_class = 'required'
    1818
    1919    def confirm_login_allowed(self, user):
    20         if not user.is_active or not user.is_staff:
     20        self.request.user = user
     21        if not self.request.admin_site.has_permission(self.request):
    2122            raise forms.ValidationError(
    2223                self.error_messages['invalid_login'],
    2324                code='invalid_login',

rebasing @czpython PR it's also an option (and way cleaner as it will display a proper message)

comment:14 by Iacopo Spalletti, 9 years ago

Owner: changed from nobody to Iacopo Spalletti
Status: newassigned

comment:15 by Tim Graham, 7 years ago

Keywords: nfa-someday removed
Summary: Bug with has_permission method of AdminSite class.Login page is redisplayed without any message if AdminSite.has_permission() returns False
Version: newforms-adminmaster

This may be addressed by #25163 which added this message to the login page if AdminSite.has_permission() returns False:

You are authenticated as <username>, but are not authorized to access this page. Would you like to login to a different account?

I haven't checked if the previously proposed patches might be a further improvement.

comment:16 by Mariusz Felisiak, 20 months ago

Owner: Iacopo Spalletti removed
Status: assignednew
Note: See TracTickets for help on using tickets.
Back to Top