IdentityPython / djangosaml2

Django SAML2 Service Provider based on pySAML2

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Loss of session data after log in

Amable-Valdes opened this issue · comments

Hello everyone!

I'm afraid I have a problem that I'm not able to solve. You will see: I have a development in which I save data in the user's session before log in through SAML. Once I log in on the IdP successfuly, the session changes and I lose my important old data :(

I've made a sketch to show you what I want to achieve:

saml_diagram

Before log in I have a sessionid with the value "kvdtu6ctgiau6oz8ru7qayokny733iag" (this session would have my data X, Y and Z). After successfully log in, I have a sessionid with the value "v5lkheyoqvfsxkclmt54g4pqyh2wwzoq", a session which the user's information from the IdP, but having lost all the data that was there before...

I have tested it with django 2.2.24 (project requisites...) and djangosaml2 v0.19, v0.40 and v1.0.0, all with the same result: the lost of the session old data.

Is this a feature? Do you know how I could keep my information safe and recover it after log in? Could I solve this with a djangosaml2 configuration?

We have a specialized cookie (samesite resistant) here
https://github.com/IdentityPython/djangosaml2/blob/master/djangosaml2/middleware.py

as we can read it, we use this cookie
https://github.com/IdentityPython/djangosaml2/blob/master/djangosaml2/views.py

here we authenticate the user after a succesfull saml2 authentication
https://github.com/IdentityPython/djangosaml2/blob/master/djangosaml2/views.py#L553

from that line to the like 577 you can inspect with a debugger what's wrong with your setup

let us know

One possible problem could be that SESSION_COOKIE_SECURE is not set to True by default in django. As djangosaml2 reuses this variable, by default the cookie will be sent with SameSite=None and Secure=False, leading to denial by recent browsers (you can check this in the Network-Tab of a Inspector for the ACS-Response).

I'd suggest a warning to be issued iff SESSION_COOKIE_SECURE is not set to True

This aspect is covered in the docs, here
https://github.com/IdentityPython/djangosaml2/blob/master/docs/source/contents/setup.rst#samesite-cookie

However I believe that your proposal is interesting, would you like to push a contribution and enable the warning message if the cookie is not secured?

I'm sorry to be late. 3 interesting weeks jejeje

Sadly, i couldn't debug the problem because the software i'm implementing is encapsulated on docker and i can't run it on local. I could attach to the process and debug it that way, but i tried other solution (that i will explain later) and it worked for now so was not needed.

First of all, I checked the code (djangosaml2/middleware.py) and everything seems fine. I didn't really find the problem this way. I thought maybe it was because I'm using an older version of djangosaml2, but I checked the same middleware in v1.0 and it seems the same...

I tried different settings: SESSION_COOKIE_SECURE was True and I had my own SAML_SESSION_COOKIE_NAME as the documentation explains, but it keeps losing data after the login.

In the end I decided to be creative; with the middleware code and some documentation from the internet (https://stackoverflow.com/questions/3862888/different-sessions-for-admin-and-applications-in-django) I created my own cookie where I save all the data I wanted to preserve after the login:

class CustomMiddleware(SessionMiddleware):

    def process_request(self, request):
        engine = import_module(settings.SESSION_ENGINE)
        session_key = request.COOKIES.get("my_custom_session_id", None)
        request.my_custom_session = engine.SessionStore(session_key)

    def process_response(self, request, response):
        try:
            accessed = request.my_custom_session.accessed
            modified = request.my_custom_session.modified
        except AttributeError:
            pass
        else:
            if accessed:
                patch_vary_headers(response, ('Cookie',))
            if modified or settings.SESSION_SAVE_EVERY_REQUEST:
                if request.my_custom_session.get_expire_at_browser_close():
                    max_age = None
                    expires = None
                else:
                    max_age = request.my_custom_session.get_expiry_age()
                    expires_time = time.time() + max_age
                    expires = cookie_date(expires_time)
                if response.status_code != 500:
                    request.my_custom_session.save()
                    response.set_cookie("my_custom_session_id",
                            request.my_custom_session.session_key, max_age=max_age,
                            expires=expires, domain=settings.SESSION_COOKIE_DOMAIN,
                            path=settings.SESSION_COOKIE_PATH,
                            secure=settings.SESSION_COOKIE_SECURE or None,
                            httponly=settings.SESSION_COOKIE_HTTPONLY or None)
        return response

That way, it worked for me; the sessionid of my_custom_session is not deleted and there are two cookies on the app: my_custom_session (where I can access all the data before and after the login) and the cookie defined in SAML_SESSION_COOKIE_NAME (where I have the login details of the user) .

If someone reading me has this problem, I solved it this way, but this is like killing a fly with a sledgehammer... Give me some time and I'll try in my spare time to replicate this problem in a simpler project to debug it, share it and find a better solution. I'm also sorry that I can't share the code for this project because it's a company software code and I can't share it.