Giter Site home page Giter Site logo

Login view request about django-sesame HOT 11 CLOSED

danizen avatar danizen commented on June 16, 2024
Login view request

from django-sesame.

Comments (11)

danizen avatar danizen commented on June 16, 2024

So, guess the view could use the LOGOUT_REDIRECT_URL Django setting in the event of a failure.
In the events of a success, it could use the LOGIN_REDIRECT_URL or "next".

from django-sesame.

aaugustin avatar aaugustin commented on June 16, 2024

I think that's a valid feature request.

from django-sesame.

aaugustin avatar aaugustin commented on June 16, 2024

Let's go back to the use case in order to clarify the constraints. The goal is to provide an alternative login mechanism via django-sesame, typically for "service account"-style access, when adding the django-sesame middleware isn't desirable.

(Here the reason for not adding the django-sesame middleware is to avoid deploying that login mechanism to all URLs. I see it as a layer of defense-in-depth on top of django-sesame, which is a more risky authentication mechanism.)


For testing purposes, you don't really care about redirecting. Your testing script can simply navigate to the next URL. Redirecting after login is a rats nest — see Django's LoginView — so I'd rather avoid it.

Your implementation looks correct to me (although I don't understand why you need the if not request.user.is_anonymous conditional). Here's a slightly more generic version, without redirects (untested):

from http import HTTPStatus

from django.contrib.auth import authenticate, login
from django.http import HttpResponse

from . import settings

def login(request, scope="", max_age=None):
    sesame = request.GET.get(settings.TOKEN_NAME)
    if sesame is None:
        return HttpResponse(
            b"login failed: missing token",
            content_type="text/plain; charset=utf-8",
            status=HTTPStatus.UNAUTHORIZED,
        )

    user = authenticate(request, sesame=sesame, scope=scope, max_age=max_age)
    if user is None:
        return HttpResponse(
            b"login failed: invalid token",
            content_type="text/plain; charset=utf-8",
            status=HTTPStatus.FORBIDDEN,
        )

    login(request, user)  # always updates the last login date.
    return HttpResponse(status=HTTPStatus.NO_CONTENT)

Going through the higher-level get_user function isn't really simpler. The primary purpose of get_user is to update the last login date, but login does that already, so you have to tell get_user not to do it. This isn't an improvement over the previous version (untested):

from http import HTTPStatus

from django.contrib.auth import login
from django.http import HttpResponse

from .utils import get_user

def login(request, scope="", max_age=None):
    # login(request, user) will update the last login date.
    user = get_user(request, update_last_login=False, scope=scope, max_age=max_age)
    if user is None:
        return HttpResponse(
            b"login failed: invalid or missing token",
            content_type="text/plain; charset=utf-8",
            status=HTTPStatus.FORBIDDEN,
        )
    login(request, user)
    return HttpResponse(status=HTTPStatus.NO_CONTENT)

Probably that solves your use case. However, I'm not sure it's sufficiently widely useful to be provided in django-sesame. For non-scripted use cases, I need to support redirecting to a customizable URL.

from django-sesame.

danizen avatar danizen commented on June 16, 2024

I agree with you on avoiding get_user().

I understand that many users of django-sesame use it not for functional testing, or to login for dynamic security analysis, but to be able to enable email based login for tickler emails. This reduces the costs of conversions in much the same way as social login does. No one likes it when the first thing an email does is demand that you login.

What about setting that restricts the middleware to work only on certain request PATHs? That is present in django-cas-ng, which is what our federated login uses on-premise (see https://www.danizen.net/anti-social-auth/). This for instance allows login to be restricted to the django admin.

from django-sesame.

danizen avatar danizen commented on June 16, 2024

Sorry, I meant "a setting" that restricts the middleware, such as SESAME_PATH_STARTS_WITH, which would default to None. It seems to me that this limits the amount of code surface for you to maintain while also enabling django-sesame to be used out of the box for this use case. To be honest, it is not just my code that restricts this login to a certain subnet - my DevOps does this as a control so that public apps can have "internal-only" URLs - sort as a "technical control" if you speak that compliance/security language.

from django-sesame.

danizen avatar danizen commented on June 16, 2024

When I first used django-sesame, set_unusable_password didn't exist, and it wasn't the default. My management commands in the common code that supports my applications probably do not call set_unusable _password. I will fix that :)

If you do not like the idea of adding a setting like SESAME_PATH_STARTS_WITH, please go ahead and close with such a comment. If you do like it, I will be happy to craft a pull request or simply wait for you or one of your maintainers/contributers.

from django-sesame.

aaugustin avatar aaugustin commented on June 16, 2024

Yesterday I attempted to clean up how Django implements redirects after login/logout: django/django#15608. This makes it much more realistic to implement a custom login view in django-sesame that redirects securely, by backporting or importing the mixin that I created in this PR. Let's see where that goes.


Then, I've been giving this further thought. Actually, it's a really good issue because it forces a more structured understanding of use cases for django-sesame.

Users may want:

  • permanent authentication ("log the user in with django.contrib.auth/sessions") or temporary authentication ("just give me a user for this request")
  • global authentication ("every page on the website") or local authentication ("just a few pages")

The corresponding solutions are:

  1. permanent x global: use the middleware
  2. permanent x local: this is the feature requested here
    • the code samples discussed above support this use case with a dedicated login view
    • it would be possible to provide a decorator for this
      • pro: it would result in shorter URLs (/target?sesame=... instead of /sesame_login?sesame=...&next=%2ftarget)
      • con: it would generate security sensitive events (logging in)
        as a side-effect of GET requests on regular URLs, reviving some of the concerns with the middleware approach
  3. temporary x global: not supported
    • I'm not sure about use cases for this; it might be useful if you want short lived authentication (via short lived tokens) anywhere but you don't want to upgrade it to long lived authentication (via sessions); does anyone want this?
  4. temporary x local: use user = get_user(request)
    • it would be possible to provide a decorator for this
      • this raises a few questions e.g. what if another user is already logged in but no obvious blocker

Long story short, here's one possible plan:

  • Restructure README to clarify use cases & appropriate APIs
  • Add a login view for the permanent x local use case
  • Consider adding a decorator as an alternative solution for the permanent x local use case (= either do it or file an issue for later)
  • Consider adding a decorator for the temporary x local use case (same)

from django-sesame.

aaugustin avatar aaugustin commented on June 16, 2024

One thing I didn't address — I dislike the idea of a setting containing of whitelist of URLs; this is too far from the URLconf or the view. I'd rather apply a decorator in the URLconf or directly on the view.

from django-sesame.

danizen avatar danizen commented on June 16, 2024

I dislike the idea of a setting containing of whitelist of URLs; this is too far from the URLconf or the view. I'd rather apply a decorator in the URLconf or directly on the view.

I see that - spreading it out into middleware, URLconf, and the views undermines the clarity of the code. A security professional might talk about increasing attack surface. I used to advocate that many developers apply security decorators directly in URLconf so that they can validate security in one file - but I found it too convenient personally to do that in the views once I understood "@method_decorator", and also DRF with authentication classes makes that sort of difficult anyway.

from django-sesame.

aaugustin avatar aaugustin commented on June 16, 2024

Hello @danizen, what do you think of #83?

I haven't written the documentation yet; you can look at the tests for intended usage.

from django-sesame.

danizen avatar danizen commented on June 16, 2024

I should have followed up on this. NIH Central IT created an "Automated Login Utility" which works for both Django and other web frameworks. The way it works is by saving a cookie (which can be moved from the browser to some automated session or used via Selenium so that when Django redirects to the usually interactive federated login, the login flows right through.

This addresses the issue I had. However, I will still try this out and get you feedback.

from django-sesame.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.