python-social-auth / social-examples

Python Social Auth - Examples
BSD 3-Clause "New" or "Revised" License
87 stars 27 forks source link

AuthMissingParameter caused by partial token clean up #6

Closed jaywhy13 closed 3 years ago

jaywhy13 commented 4 years ago

The Problem

I created this PR to demonstrate a scenario in which the AuthMissingParameter happens. This is caused by the logic here that removes the partial_token from the session without checking that the correct token is being removed.

    def clean_partial_pipeline(self, token):
        # this is the actual Partial object being removed, so this is fine
        self.storage.partial.destroy(token) 
        # THIS however doesn't check which token is being removed.. THIS is the problem
        self.session_pop(PARTIAL_TOKEN_SESSION_NAME)

It really should be something like...

    def clean_partial_pipeline(self, token):
        self.storage.partial.destroy(token)
        if self.session_get((PARTIAL_TOKEN_SESSION_NAME) == token:
           self.session_pop(PARTIAL_TOKEN_SESSION_NAME)

This only manifests itself when you leave the pipeline more than once, each with functions that save partial data. The problem is that the partial_token for the second step of the pipeline gets cleaned up when the partial_token for the first partial function is being removed.

In essence this clean up sequence is caused because the partial for the next step is saved before the clean up happens. Now because this logic doesn't look at the partial_token on the session, it inadvertently ends up cleaning up the wrong token. It cleans up the new token.

The Workaround

It's possible to work around this problem (as this repo does) by always passing up the partial_token in the /complete/<backend>/ endpoint so that Social Core is able to load the right partial token.

To show the problem, we simply need to stop doing that. For this PR, the Django home.html template was edited and I removed all the lines that added the partial_token to the form.

<input type="hidden" name="partial_token" value="{{ partial_token }}">

In this case I removed it for Country, City and Email. I was able to reproduce by connecting a Google Account. It prompts for Country and City, then gives us the AuthMissingParameter error.

The Fix

Change the logic to check the token in the session to prevent popping the wrong token.

    def clean_partial_pipeline(self, token):
        self.storage.partial.destroy(token)
        current_token_in_session = self.session_get(PARTIAL_TOKEN_SESSION_NAME)
        if current_token_in_session == token:
            self.session_pop(PARTIAL_TOKEN_SESSION_NAME)

I have a branch with the fix. This commit can be directly installed to test drive the fix.

pip install -e git+git://github.com/jaywhy13/social-core.git@561642bf7ea079cdf57ff0fda15c74a1fcc5eba4#egg=social-core
jaywhy13 commented 3 years ago

Closing this as was just for demonstration.