dpgaspar / Flask-AppBuilder

Simple and rapid application development framework, built on top of Flask. includes detailed security, auto CRUD generation for your models, google charts and much more. Demo (login with guest/welcome) - http://flaskappbuilder.pythonanywhere.com/
BSD 3-Clause "New" or "Revised" License
4.63k stars 1.35k forks source link

Make Google OAuth login work for users created using `create-user` #2172

Open jainankit opened 9 months ago

jainankit commented 9 months ago

Hey folks, looks like there is no good way to access control the app to a subset of users when using Google OAuth. What we are trying to achieve is restrict either users with a particular domain @example.com, or manually add new users using flask fab create -user command.

The issue is that during OAuth, FAB set the userinfo for Google as:

            return {
                "username": "google_" + data.get("id", ""),
                "first_name": data.get("given_name", ""),
                "last_name": data.get("family_name", ""),
                "email": data.get("email", ""),
            }

and then when validating, it validates whether username google_<id> exist in the database. If we create users manually, we only know the email address and not the Google's user.id. Typically we are doing:

flask fab create-user --username helloworld --email hello@example.com --firstname hello --lastname world

If we switch the lookup in the database to both username and email based, this issue can be resolved:

    def auth_user_oauth(self, userinfo):
        username = None
        email = None
        user = None
        if "username" in userinfo:
            username = userinfo["username"]
            if username:
              user = self.find_user(username=username)
        if user is None and "email" in userinfo:
            email = userinfo["email"]
            if email:
               user = self.find_user(email=email)
        else:
            log.error("OAUTH userinfo does not have username or email %s", userinfo)
            return None

        # If username and email is empty, go away
        if not username and not email:
            return None

Environment

Flask-Appbuilder version: v4.3.10

Describe the expected results

We should be able to let users created using create-user to login via OAuth

Describe the actual results

User not able to login, and the authentication fails because then there's a conflict with an existing email address associated with the user we created manually.

Steps to reproduce

Set up Google OAuth, and create the user using flask fab create-user before logging in.

PS: I can also send out a fix for this if the issue is accepted.