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()
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
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()
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()
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