From 6df2043e4d8024fb8476256349a950a2949ab292 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Sun, 10 Dec 2017 16:46:43 +0100 Subject: [PATCH] Remove community authentication 1.0 Community authentication 1.0 relied on PostgreSQL connections between all servers, and hasn't been used for years. This includes removing the code that migrates users from the old community authentication system to the new one. This means that any user who has not logged in since 2011 will no longer be able to user their oan account, and have to create a new one. --- docs/authentication.rst | 27 -------- pgweb/util/auth.py | 37 +---------- sql/community_login.sql | 144 ---------------------------------------- 3 files changed, 3 insertions(+), 205 deletions(-) diff --git a/docs/authentication.rst b/docs/authentication.rst index 66fe44a6..8c43294b 100644 --- a/docs/authentication.rst +++ b/docs/authentication.rst @@ -1,25 +1,3 @@ -Authentication -============== -The authentication system provides the base for the community login -system, as well as the django system. The functions defined in -sql/community_login.sql implement the community login system (existing -API) on top of the django authentication, as well as a function to -access all users defined in the old community login system. - -The custom authentication provider pgweb.util.auth.AuthBackend -implements the community login system migration functionality. It will -first attempt to log the user in with the standard django system. If -this fails, it will attempt to log the user in with the *old* -community login system, and if this succeeds the user will -automatically be migrated to the django authentication system, and -removed from the old system. - -In a local installation that does not have access to the existing set -of users, this authentication backend can be disabled completely, and -the system will function perfectly fine relying on just the django -authentication system. - - Community authentication 2.0 ============================ While the old community authentication system was simply having the @@ -39,11 +17,6 @@ encryption keys and similar details. This is now held in the main database, accessible through the django administration system, instead of being held in pg_hba.conf and managed through SQL. -In some cases this may be complicated to implement on the client side, -and thus version 1.0 community login is still left around. It may -be removed at some point in the future, depending on implementation -and policy details... - The flow of an authentication in the 2.0 system is fairly simple: #. The user tries to access a protected resource on the community diff --git a/pgweb/util/auth.py b/pgweb/util/auth.py index 2712b91c..d476f0ee 100644 --- a/pgweb/util/auth.py +++ b/pgweb/util/auth.py @@ -4,9 +4,8 @@ from django.db import connection from pgweb.core.models import UserProfile -# Special version of the authentication backend, so we can deal with migration -# of accounts from the old community login system. Once we consider all accounts -# migrated, we can remove this one and use the default backend. +# Special version of the authentication backend, so we can handle things like +# forced lowercasing of usernames. class AuthBackend(ModelBackend): def authenticate(self, username=None, password=None): try: @@ -20,37 +19,7 @@ class AuthBackend(ModelBackend): # User found but password wrong --> tell django it is wrong return None except User.DoesNotExist: - # User does not exist. See if it exists in the old system, - # and if it does, migrate it to the new one. - curs = connection.cursor() - curs.execute('SELECT * FROM community_login_old(%s,%s)', (username.lower(), password)) - rows = curs.fetchall() - - if len(rows) != 1: - # No rows returned, something clearly went wrong - return None - if rows[0][1] == 1: - # Value 1 in field 1 means the login succeeded. In this case, - # create a user in the django system, and migrate all settings - # we can think of. - namepieces = rows[0][2].split(None, 2) - if len(namepieces) == 0: namepieces = ['', ''] - if len(namepieces) == 1: namepieces.append('') - user = User(username=username.lower(), email=rows[0][3], first_name=namepieces[0], last_name=namepieces[1]) - user.set_password(password) - user.save() - - # Create a userprofile if we have to - if rows[0][8]: - profile = UserProfile(user=user) - profile.sshkey = rows[0][8] - profile.save() - - # Now delete the user in the old system so nobody can use it - curs.execute('SELECT * FROM community_login_old_delete(%s)', (username.lower(), )) - - return user - # Any other value in field 1 means login failed, so tell django we did + # User not found, so clearly they can't log in! return None return None # Should never get here, but just in case... diff --git a/sql/community_login.sql b/sql/community_login.sql index fffe79f2..7f688db9 100644 --- a/sql/community_login.sql +++ b/sql/community_login.sql @@ -1,147 +1,3 @@ -BEGIN; - --- --- Log the user in, using the django auth system --- -CREATE OR REPLACE FUNCTION community_login(INOUT userid_p text, password_p text, - OUT success integer, OUT fullname text, OUT email text, OUT authorblurb text, - OUT communitydoc_superuser integer, OUT _last_login timestamp with time zone, - OUT matrixeditor integer) -RETURNS record -AS $$ -DECLARE - stored_userid text; - stored_fullname text; - stored_email text; - stored_lastlogin timestamptz; - stored_pwd text; -BEGIN - -- Lecagy parameters from previous versions - authorblurb := ''; - communitydoc_superuser := 0; - matrixeditor := 0; - - -- Look for user - SELECT - lower(auth_user.username), - trim(auth_user.first_name || ' ' || auth_user.last_name), - auth_user.email, - last_login, - auth_user.password - INTO stored_userid,stored_fullname,stored_email,stored_lastlogin,stored_pwd - FROM auth_user WHERE - lower(auth_user.username) = lower(userid_p); - IF FOUND THEN - -- User exists, verify password - IF encode(pgcrypto.digest(split_part(stored_pwd, '$', 2) || password_p, 'sha1'), 'hex') = split_part(stored_pwd, '$', 3) THEN - success := 1; - userid_p := stored_userid; - fullname := stored_fullname; - email := stored_email; - _last_login := stored_lastlogin; - UPDATE auth_user SET last_login=CURRENT_TIMESTAMP WHERE auth_user.username=stored_userid; - ELSE - -- User exists, but wrong password - success := 0; - END IF; - ELSE - -- User does not exist, look it up in the old system. - -- XXX: we don't support migrating users yet, should we? currently - -- they are only migrated when they log into the main website. - SELECT users_old.userid,users_old.fullname,users_old.email,users_old.lastlogin - INTO stored_userid,stored_fullname,stored_email,stored_lastlogin - FROM users_old WHERE lower(users_old.userid)=lower(userid_p) AND - substring(users_old.pwdhash, 30) = pgcrypto.crypt(password_p, substring(users_old.pwdhash, 1, 29)); - IF FOUND THEN - success := 1; - userid_p := stored_userid; - fullname := stored_fullname; - email := stored_email; - _last_login := stored_lastlogin; - UPDATE users_old SET lastlogin=CURRENT_TIMESTAMP WHERE users_old.userid=stored_userid; - ELSE - success := 0; - END IF; - END IF; -END -$$ -LANGUAGE 'plpgsql' SECURITY DEFINER; - - --- --- Create new user - not implemented --- -CREATE OR REPLACE FUNCTION community_login_create(_userid text, _password text, _fullname text, _email text) -RETURNS boolean -AS $$ - SELECT 'f'::boolean; -$$ LANGUAGE 'sql'; - --- --- Check if a user exists --- -CREATE OR REPLACE FUNCTION community_login_exists(userid text) -RETURNS boolean -AS $$ - SELECT EXISTS (SELECT 1 FROM auth_user WHERE lower(username)=lower($1) UNION ALL SELECT 1 from users_old where userid=lower($1)); -$$ LANGUAGE 'sql'; - --- --- Update user information - not implemented, edits should be through website --- -CREATE OR REPLACE FUNCTION community_login_setinfo(_userid text, _password text, - _fullname text, _email text, _authorblurb text) -RETURNS boolean -AS $$ - SELECT 'f'::boolean -$$ LANGUAGE 'sql'; - --- --- Change user password - not implemented, edits should be through website --- -CREATE OR REPLACE FUNCTION community_login_setpassword(_userid text, _password text) -RETURNS boolean -AS $$ - SELECT 'f'::boolean; -$$ LANGUAGE 'sql'; - --- --- Replica of the old login functionality. Only used so we can migreate the user --- -CREATE OR REPLACE FUNCTION community_login_old(INOUT userid_p text, password_p text, - OUT success integer, OUT fullname text, OUT email text, OUT authorblurb text, - OUT communitydoc_superuser integer, OUT last_login timestamp with time zone, - OUT matrixeditor integer, OUT sshkey text) -RETURNS record -AS $$ -BEGIN - SELECT users_old.userid,users_old.fullname,users_old.email,users_old.authorblurb,users_old.communitydoc_superuser,users_old.lastlogin,users_old.matrixeditor,users_old.sshkey - INTO userid_p,fullname,email,authorblurb,communitydoc_superuser,last_login,matrixeditor, sshkey - FROM users_old WHERE lower(users_old.userid)=lower(userid_p) AND - substring(users_old.pwdhash, 30) = pgcrypto.crypt(password_p, substring(users_old.pwdhash, 1, 29)); --- bf salts are always 29 chars! - IF FOUND THEN - success := 1; - ELSE - success := 0; - END IF; -END -$$ -LANGUAGE plpgsql SECURITY DEFINER; - --- --- Delete an account from the old system --- -CREATE OR REPLACE FUNCTION community_login_old_delete(userid text) -RETURNS void -AS $$ - DELETE FROM users_old WHERE userid=$1; -$$ -LANGUAGE sql; - -COMMIT; - - -- -- View that shows the ssh keys, used by services that need them -- (currently just git) -- 2.39.5