Example #1
0
    def process(self, db, user, req, username, password):
        if not user.isAnonymous():
            if user.name == username:
                return OperationResult()
            else:
                return OperationResult(message="Already signed as '%s'!" % user.name)

        try:
            user = auth.checkPassword(db, username, password)
        except auth.NoSuchUser:
            return OperationResult(message="No such user!")
        except auth.WrongPassword:
            return OperationResult(message="Wrong password!")

        auth.startSession(db, req, user)

        db.commit()

        return OperationResult()
Example #2
0
    def process(self, db, user, req, username, password):
        if not user.isAnonymous():
            if user.name == username:
                return OperationResult()
            else:
                return OperationResult(message="Already signed as '%s'!" %
                                       user.name)

        try:
            user = auth.checkPassword(db, username, password)
        except auth.NoSuchUser:
            return OperationResult(message="No such user!")
        except auth.WrongPassword:
            return OperationResult(message="Wrong password!")

        auth.startSession(db, req, user)

        db.commit()

        return OperationResult()
Example #3
0
    def finish(self, db, req):
        if req.method != "GET":
            raise auth.InvalidRequest

        code = req.getParameter("code", default=None)
        state = req.getParameter("state", default=None)

        if code is None or state is None:
            raise auth.InvalidRequest("Missing parameter(s)")

        cursor = db.cursor()
        cursor.execute("""SELECT url
                            FROM oauthstates
                           WHERE state=%s""",
                       (state,))

        row = cursor.fetchone()

        if not row:
            raise auth.InvalidRequest("Invalid OAuth state: %s" % state)

        (target_url,) = row

        access_token = self.getAccessToken(code)

        if access_token is None:
            raise auth.Failure("failed to get access token")

        user_data = self.getUserData(access_token)

        if user_data is None:
            raise auth.Failure("failed to get user data")

        account = textutils.encode(user_data["account"])
        username = textutils.encode(user_data["username"])
        email = user_data["email"]
        email = textutils.encode(email) if email else None
        fullname = textutils.encode(user_data.get("fullname", username))

        cursor.execute("""SELECT id, uid
                            FROM externalusers
                           WHERE provider=%s
                             AND account=%s""",
                       (self.name, account))

        row = cursor.fetchone()

        if not row:
            cursor.execute("""INSERT INTO externalusers (provider, account, email)
                                   VALUES (%s, %s, %s)
                                RETURNING id""",
                           (self.name, account, email))

            row = (cursor.fetchone()[0], None)

        external_user_id, user_id = row
        user = None

        if user_id is None:
            if auth.isValidUserName(username) \
                    and self.configuration.get("bypass_createuser"):
                try:
                    dbutils.User.fromName(db, username)
                except dbutils.NoSuchUser:
                    user = dbutils.User.create(db, username, fullname, email, None)
                    cursor.execute("""UPDATE externalusers
                                         SET uid=%s
                                       WHERE id=%s""",
                                   (user.id, external_user_id))
                    user.sendUserCreatedMail("wsgi[oauth/%s]" % self.name,
                                             { "provider": self.name,
                                               "account": account })
        else:
            user = dbutils.User.fromId(db, user_id)

        if user is not None:
            auth.startSession(db, req, user)
        else:
            token = auth.getToken()

            cursor.execute("""UPDATE externalusers
                                 SET token=%s
                               WHERE id=%s""",
                           (token, external_user_id))

            data = { "provider": self.name,
                     "account": account,
                     "token": token }

            if target_url:
                data["target"] = target_url
            if username:
                data["username"] = username
            if email:
                data["email"] = email
            if fullname:
                data["fullname"] = fullname

            target_url = "/createuser?%s" % urllib.urlencode(data)

        req.setStatus(302)
        req.addResponseHeader("Location", target_url or "/")
        req.start()

        db.commit()

        return True
Example #4
0
    def process(self,
                db,
                user,
                req,
                username,
                fullname,
                email,
                password=None,
                external=None):
        cursor = db.cursor()

        if not fullname:
            fullname = username
        if not email:
            email = None
        if not password:
            # Empty password => disabled.
            password = None

        if external:
            provider_config = configuration.auth.PROVIDERS[
                external["provider"]]
            provider = auth.PROVIDERS[external["provider"]]

        # Check that user registration is actually enabled.  This would also
        # disable the UI for user registration, of course, but the UI could be
        # bypassed, so we should check here as well.
        if not configuration.base.ALLOW_USER_REGISTRATION:
            if not external or not provider_config["allow_user_registration"]:
                return OperationResult(
                    message="User registration is not enabled.")

        # Check that the user name is valid.
        try:
            auth.validateUserName(username)
        except auth.InvalidUserName as error:
            return OperationResult(message="<u>Invalid user name</u><br>" +
                                   str(error),
                                   focus="#newusername")

        # Check that the user name is not already taken.
        cursor.execute("SELECT 1 FROM users WHERE name=%s", (username, ))
        if cursor.fetchone():
            return OperationResult(
                message="A user named '%s' already exists!" % username,
                focus="#newusername")

        # Check that the email address has some hope of being valid.
        if email and not checkEmailAddressSyntax(email):
            return OperationResult(
                message=("<u>Invalid email address</u><br>"
                         "Please provide an address on the form user@host!"),
                focus="#email")

        # Check that we have either a password or an external authentication
        # provider.  If we have neither, the user wouldn't be able to sign in.
        if password is None and external is None:
            return OperationResult(message="Empty password.",
                                   focus="#password1")

        if password:
            password = auth.hashPassword(password)

        verify_email_address = configuration.base.VERIFY_EMAIL_ADDRESSES

        if external:
            # Check that the external authentication token is valid.
            if not provider.validateToken(db, external["account"],
                                          external["token"]):
                return OperationResult(
                    message="Invalid external authentication state.")

            cursor.execute(
                """SELECT id, uid, email
                                FROM externalusers
                               WHERE provider=%s
                                 AND account=%s""",
                (external["provider"], external["account"]))

            # Note: the token validation above implicitly checks that there's a
            # matching row in the 'externalusers' table.
            external_user_id, existing_user_id, external_email = cursor.fetchone(
            )

            # Check that we don't already have a Critic user associated with
            # this external user.
            if existing_user_id is not None:
                existing_user = dbutils.User.fromId(db, existing_user_id)
                return OperationResult(
                    message=("There is already a Critic user ('%s') connected "
                             "to the %s '%s'" %
                             (existing_user.name, provider.getTitle(),
                              external["account"])))

            if email == external_email:
                verify_email_address = provider.configuration[
                    "verify_email_addresses"]

            # Reset 'email' column in 'externalusers': we only need it to detect
            # if the user changed the email address in the "Create user" form.
            # Also reset the 'token' column, which serves no further purpose
            # beyond this point.
            cursor.execute(
                """UPDATE externalusers
                                 SET email=NULL,
                                     token=NULL
                               WHERE id=%s""", (external_user_id, ))

        email_verified = False if email and verify_email_address else None

        user = dbutils.User.create(db, username, fullname, email,
                                   email_verified, password)

        if external:
            cursor.execute(
                """UPDATE externalusers
                                 SET uid=%s
                               WHERE id=%s""", (user.id, external_user_id))

        auth.startSession(db, req, user)

        if email_verified is False:
            sendVerificationMail(db, user)

        db.commit()

        user.sendUserCreatedMail("wsgi[registeruser]", external)

        return OperationResult()
Example #5
0
    def process(self, db, user, req, username, fullname, email,
                password=None, external=None):
        cursor = db.cursor()

        if not fullname:
            fullname = username
        if not email:
            email = None
        if not password:
            # Empty password => disabled.
            password = None

        if external:
            provider_config = configuration.auth.PROVIDERS[external["provider"]]
            provider = auth.PROVIDERS[external["provider"]]

        # Check that user registration is actually enabled.  This would also
        # disable the UI for user registration, of course, but the UI could be
        # bypassed, so we should check here as well.
        if not configuration.base.ALLOW_USER_REGISTRATION:
            if not external or not provider_config["allow_user_registration"]:
                return OperationResult(
                    message="User registration is not enabled.")

        # Check that the user name is valid.
        try:
            auth.validateUserName(username)
        except auth.InvalidUserName as error:
            return OperationResult(
                message="<u>Invalid user name</u><br>" + str(error),
                focus="#newusername")

        # Check that the user name is not already taken.
        cursor.execute("SELECT 1 FROM users WHERE name=%s", (username,))
        if cursor.fetchone():
            return OperationResult(
                message="A user named '%s' already exists!" % username,
                focus="#newusername")

        # Check that the email address has some hope of being valid.
        if email and not checkEmailAddressSyntax(email):
            return OperationResult(
                message=("<u>Invalid email address</u><br>"
                         "Please provide an address on the form user@host!"),
                focus="#email")

        # Check that we have either a password or an external authentication
        # provider.  If we have neither, the user wouldn't be able to sign in.
        if password is None and external is None:
            return OperationResult(
                message="Empty password.",
                focus="#password1")

        if password:
            password = auth.hashPassword(password)

        verify_email_address = configuration.base.VERIFY_EMAIL_ADDRESSES

        if external:
            # Check that the external authentication token is valid.
            if not provider.validateToken(db, external["account"],
                                          external["token"]):
                return OperationResult(
                    message="Invalid external authentication state.")

            cursor.execute("""SELECT id, uid, email
                                FROM externalusers
                               WHERE provider=%s
                                 AND account=%s""",
                           (external["provider"], external["account"]))

            # Note: the token validation above implicitly checks that there's a
            # matching row in the 'externalusers' table.
            external_user_id, existing_user_id, external_email = cursor.fetchone()

            # Check that we don't already have a Critic user associated with
            # this external user.
            if existing_user_id is not None:
                existing_user = dbutils.User.fromId(db, existing_user_id)
                return OperationResult(
                    message=("There is already a Critic user ('%s') connected "
                             "to the %s '%s'" % (existing_user.name,
                                                 provider.getTitle(),
                                                 external["account"])))

            if email == external_email:
                verify_email_address = provider.configuration["verify_email_addresses"]

            # Reset 'email' column in 'externalusers': we only need it to detect
            # if the user changed the email address in the "Create user" form.
            # Also reset the 'token' column, which serves no further purpose
            # beyond this point.
            cursor.execute("""UPDATE externalusers
                                 SET email=NULL,
                                     token=NULL
                               WHERE id=%s""",
                           (external_user_id,))

        email_verified = False if email and verify_email_address else None

        user = dbutils.User.create(
            db, username, fullname, email, email_verified, password)

        if external:
            cursor.execute("""UPDATE externalusers
                                 SET uid=%s
                               WHERE id=%s""",
                           (user.id, external_user_id))

        auth.startSession(db, req, user)

        if email_verified is False:
            sendVerificationMail(db, user)

        db.commit()

        user.sendUserCreatedMail("wsgi[registeruser]", external)

        return OperationResult()
Example #6
0
    def finish(self, db, req):
        if req.method != "GET":
            raise auth.InvalidRequest

        code = req.getParameter("code", default=None)
        state = req.getParameter("state", default=None)

        if code is None or state is None:
            raise auth.InvalidRequest("Missing parameter(s)")

        cursor = db.cursor()
        cursor.execute(
            """SELECT url
                            FROM oauthstates
                           WHERE state=%s""", (state, ))

        row = cursor.fetchone()

        if not row:
            raise auth.InvalidRequest("Invalid OAuth state: %s" % state)

        (target_url, ) = row

        access_token = self.getAccessToken(code)

        if access_token is None:
            raise auth.Failure("failed to get access token")

        user_data = self.getUserData(access_token)

        if user_data is None:
            raise auth.Failure("failed to get user data")

        account = textutils.encode(user_data["account"])
        username = textutils.encode(user_data["username"])
        email = user_data["email"]
        email = textutils.encode(email) if email else None
        fullname = textutils.encode(user_data.get("fullname", username))

        cursor.execute(
            """SELECT id, uid
                            FROM externalusers
                           WHERE provider=%s
                             AND account=%s""", (self.name, account))

        row = cursor.fetchone()

        if not row:
            cursor.execute(
                """INSERT INTO externalusers (provider, account, email)
                                   VALUES (%s, %s, %s)
                                RETURNING id""", (self.name, account, email))

            row = (cursor.fetchone()[0], None)

        external_user_id, user_id = row
        user = None

        if user_id is None:
            if auth.isValidUserName(username) \
                    and self.configuration.get("bypass_createuser"):
                try:
                    dbutils.User.fromName(db, username)
                except dbutils.NoSuchUser:
                    user = dbutils.User.create(db, username, fullname, email,
                                               None)
                    cursor.execute(
                        """UPDATE externalusers
                                         SET uid=%s
                                       WHERE id=%s""",
                        (user.id, external_user_id))
                    user.sendUserCreatedMail("wsgi[oauth/%s]" % self.name, {
                        "provider": self.name,
                        "account": account
                    })
        else:
            user = dbutils.User.fromId(db, user_id)

        if user is not None:
            auth.startSession(db, req, user)
        else:
            token = auth.getToken()

            cursor.execute(
                """UPDATE externalusers
                                 SET token=%s
                               WHERE id=%s""", (token, external_user_id))

            data = {"provider": self.name, "account": account, "token": token}

            if target_url:
                data["target"] = target_url
            if username:
                data["username"] = username
            if email:
                data["email"] = email
            if fullname:
                data["fullname"] = fullname

            target_url = "/createuser?%s" % urllib.urlencode(data)

        req.setStatus(302)
        req.addResponseHeader("Location", target_url or "/")
        req.start()

        db.commit()

        return True