def setUserStatus(userNameOrEmail, user_id): """After the user's login has authenticated, record some values in the session. user _str_: userNameOrEmail user_id _int_: user record id user_name _str_: full name of user user_has_password _bool_: True if the user has a password also sets the globals: g.user = session["user] g.user_has_password = session["user_has_password"] """ user = User(g.db) rec = user.get(user_id) if rec: user.update_last_access(rec.id) session["user"] = userNameOrEmail.strip() session['user_id'] = rec.id session["user_name"] = "" if rec.first_name: session['user_name'] = rec.first_name + " " if rec.last_name: session["user_name"] = session["user_name"] + rec.last_name session["user_name"] = session['user_name'].strip() g.user = session["user"] g.user_has_password = session['user_has_password'] = ( rec.password != None and rec.password != '') else: flash("Unable to locate user")
def display(path=""): setExits() g.title = "{} Record List".format(g.title) user = User(g.db) user_rank = user.max_role_rank(g.user) user_list = UserView(User, g.db) return user_list.dispatch_request(include_inactive=True, user_rank=user_rank)
def validForm(rec): # Validate the form goodForm = True user = User(g.db) if request.form['email'].strip() == '': goodForm = False flash('Email may not be blank') if request.form['email'].strip() != '' and not looksLikeEmailAddress( request.form['email'].strip()): goodForm = False flash("That doesn't look like a valid email address") if request.form['email'].strip() != '': # always test lower case version of email found = user.get(request.form['email'].strip().lower(), include_inactive=True) if found: if request.form['id'] == 'None' or found.id != int( request.form['id']): goodForm = False flash('That email address is already in use') # user name must be unique if supplied if 'new_username' in request.form: if request.form['new_username'].strip() != '': found = user.get(request.form['new_username'].strip(), include_inactive=True) if found: if request.form['id'] == 'None' or found.id != int( request.form['id']): goodForm = False flash('That User Name is already in use') if request.form["new_username"].strip() != '' and request.form[ "new_password"].strip() == '' and rec.password == '': goodForm = False flash('There must be a password if there is a User Name') if request.form["new_password"].strip() == '' and request.form[ "confirm_password"].strip() != '' and rec.password != '': goodForm = False flash("You can't enter a blank password.") #passwords must match if present if request.form['confirm_password'].strip( ) != request.form['new_password'].strip(): goodForm = False flash('Passwords don\'t match.') return goodForm
def recover_password(): """Send reset password and send user an email if they forget their password""" setExits() g.title = "Reset Password" rec = None temp_pass = None email_not_found = False if not request.form: pass else: #find the user with that email rec = User(g.db).select_one(where='lower(email) = lower("{}")'.format( request.form['email'].strip().lower())) if rec == None: flash( "That email address could not be found in the list of users.") else: # generate a new password that is unique to the system temp_pass = get_access_token() # save the temporary password rec.access_token = temp_pass rec.access_token_expires = time() + (3600 * 48) # 2 days to reset User(g.db).save(rec) g.db.commit() # send an email with instructions from shotglass2.takeabeltof.mailer import send_message full_name = rec.first_name + " " + rec.last_name context = { 'temp_pass': temp_pass, 'rec': rec, 'full_name': full_name } to_address_list = [ (full_name, rec.email), ] result, msg = send_message( to_address_list, context=context, html_template='email/confirm_reset.html', text_template='email/confirm_reset.txt', subject='Confirm Password Reset') # Return a page telling user what we did return render_template('recover_password.html', temp_pass=temp_pass, rec=rec)
def nogood_test_list_page(client): """Right now this fails missurably, but when it was 'working' it was operating on the live database instead of the temporary one like the docs implied it would.""" with app.app.app_context(): with client as c: from flask import session, g from shotglass2.users.models import User, Role import app print(app.app.config['DATABASE_PATH']) app.get_db(app.app.config['DATABASE_PATH']) # access without login result = c.get('/user/delete/3/', follow_redirects=True) assert result.status_code == 200 assert b'Sorry. You do not have access to that page' in result.data rec = User(app.g.db).get('John') print(rec) # Login as user role result = c.post('/login/', data={ 'userNameOrEmail': 'John', 'password': '******' }, follow_redirects=True) assert result.status == '200 OK' assert b'Invalid User Name or Password' not in result.data assert session['user'] == 'John' #attempt to delete a record result = c.get('/role/delete/3/', follow_redirects=True) assert result.status_code == 200 assert b'Sorry. You do not have access to that page' in result.data
def get_user_role_names(rec): user_roles = [] roles = User(g.db).get_roles(rec.id) if roles: for x in roles: user_roles.append(x.name) return user_roles
def test_user_creation(): from shotglass2.users.models import User #create some user records user = User(db) rec = user.new() assert rec != None rec.first_name = 'Another' rec.last_name = 'User' rec.username = '******' # Spaces should be trimmed rec.email = '*****@*****.**' new_id = user.save(rec) assert new_id != None assert new_id > 0 assert rec.active == 1 #test the default value assert rec.username == 'anotheruser' db.rollback()
def has_access(self, user_name, table=None): """Test to see if the user represented by user name has access to ANY admin items If a table class is specified, only check to see if user has access to that table If 'table' is a string, look for permissions by the display_name. Useful when testing the permissions from a template where the table object is not available. """ from shotglass2.users.models import User if len(self.permissions) == 0: return False user = User(self.db) rec = user.get(user_name) if not rec or not user: return False user_roles = user.get_roles(rec.id) if not user_roles: return False temp_list = self.permissions if table: dict_item = 'table' try: if type(table) is str: # Look up the table by display name dict_item = 'display_name' temp_list = [x for x in temp_list if x[dict_item] == table] except: return False for role in user_roles: for list_item in temp_list: if role.name.lower() in list_item['roles']: return True if list_item['minimum_rank_required'] <= role.rank: return True return False
def activate(): """Allow administrator to activate a new user""" activate = request.args.get('activate', None) if activate: user = User(g.db) rec = user.select_one( where='access_token = "{}"'.format(activate.strip())) if rec: rec.active = 1 rec.access_token = None rec.access_token_expires = None user.save(rec) g.db.commit() # inform user that their account is now active full_name = '{} {}'.format(rec.first_name, rec.last_name).strip() to = [(full_name, rec.email)] context = { 'rec': rec, } subject = 'Account Activated' html_template = 'email/activation_complete.html' text_template = 'email/activation_complete.txt' send_message(to, context=context, subject=subject, html_template=html_template, text_template=text_template) else: flash("User not found with access_token: {}".format(activate)) return redirect('/') else: flash("Activation code not in request args") return redirect('/') flash("New User Activation Successful") return edit(rec.id)
def test_user_update(): from shotglass2.users.models import User user = User(db) rec = user.get('doris') assert rec != None rec.email = '*****@*****.**' user.save(rec) rec = user.get('doris') assert rec.email == '*****@*****.**' db.rollback() #test the update() method of _Table rec = user.get('doris') d = {'id':233,'address':'1234 Some Street',} user.update(rec,d,True) #save to db rec = user.get('doris') assert rec.address == '1234 Some Street' assert rec.id != 233 db.rollback()
def get_access_token(token_length=24): """Return an access token that does not exist in the user table""" from shotglass2.users.models import User temp_rec = 'temp' while temp_rec != None: access_token = "" for x in range(token_length): access_token += random.choice( 'abcdefghijklmnopqrstuvwxyz12344567890') #test that access_token is unique. break when rec == None temp_rec = User( g.db).select_one(where='access_token = "{}"'.format(access_token)) return access_token
def test_create_test_data(): # Populate the test database from shotglass2.users.models import User try: f = open(abs_path('test_data_create.sql'), 'r') sql = f.read() f.close() cur = db.cursor() cur.executescript(sql) rec = User(db).get('doris') rec.password = getPasswordHash('password') User(db).save(rec) rec = User(db).get('John') rec.password = getPasswordHash('password') User(db).save(rec) db.commit() assert True == True except: assert True == False
def test_user_delete(): from shotglass2.users.models import User, Role user = User(db) record_deleted = user.delete(2) assert record_deleted == True record_deleted = user.delete('John') assert record_deleted == True record_deleted = user.delete('John') # can't delete it twice assert record_deleted == False record_deleted = user.delete('none') # test that we can delete an inactive record assert record_deleted == True record_deleted = Role(db).delete(1) assert record_deleted == True db.rollback()
def authenticate_user(username, password, **kwargs): """ Check username and password in db and return: 0 = Authentication Failed 1 = Authentication Succeeded 2 = Need a password for this user -1 = User Inactive Optional kwargs: include_inactive = True login_on_success = True """ include_inactive = kwargs.get('include_inactive', True) login_on_success = kwargs.get('login_on_success', True) result = 0 #import pdb; pdb.set_trace() rec = User(g.db).get(username, include_inactive=include_inactive) if rec: if not rec.password: #User has no password, just login result = 1 elif not password: #need a password for this user result = 2 elif matchPasswordToHash(password, rec.password): result = 1 if rec.active != 1: result = -1 if result == 1 and rec.active == 1 and login_on_success: # use rec.username if there is one if rec.username: username = rec.username setUserStatus(username, rec.id) return result
def login(): setExits() g.user = g.get('user', None) next = request.args.get('next', request.form.get('next', '')) get_pass = request.form.get('get_pass', False) if g.user is not None: #flash("Already Logged in...") return redirect('/') if 'reset' in request.args: #Try to find the user record that requested a reset rec = User(g.db).select_one(where='access_token = "{}"'.format( request.args.get('reset', '')).strip()) if rec and rec.access_token_expires > time(): userNameOrEmail = rec.username if not userNameOrEmail: userNameOrEmail = rec.email setUserStatus(userNameOrEmail, rec.id) return redirect(url_for('user.edit')) else: flash("That reset request has expired") return redirect('/') if not request.form: if 'loginTries' not in session: session['loginTries'] = 0 if request.form: if 'loginTries' not in session: #Testing that user agent is keeping cookies. #If not, there is no point in going on... Also, could be a bot. return render_template('no-cookies.html') result = authenticate_user(request.form["userNameOrEmail"], request.form.get('password')) if result == 2: # need to get password from user get_pass = True elif result != 0: session['loginTries'] = 0 if result == -1: flash("Your account is inactive") return render_template('inactive.html') #import pdb;pdb.set_trace() if next: return redirect(next) return redirect('/') #logged in... else: flash("Invalid User Name or Password") if 'loginTries' not in session: session['loginTries'] = 0 #remember howmany times the user has tried to log in session['loginTries'] = session['loginTries'] + 1 #slow down login attempts if session['loginTries'] > 5: sleep(session['loginTries'] / .8) return render_template('login.html', form=request.form, next=next, get_pass=get_pass)
def register(): """Allow people to sign up thier own accounts on the web site""" setExits() site_config = get_site_config() g.title = "Account Registration" g.editURL = url_for('.register') g.listURL = '/' # incase user cancels user = User(g.db) rec = user.new() is_admin = False user_roles = None roles = None no_delete = True success = True help = render_markdown_for("new_account_help.md", mod) next = request.form.get('next', request.args.get('next', '')) # import pdb;pdb.set_trace() if 'confirm' in request.args: #Try to find the user record that requested registration rec = user.select_one(where='access_token = "{}"'.format( request.args.get('confirm', '')).strip()) if rec and rec.access_token_expires > time(): if site_config.get('ACTIVATE_USER_ON_CONFIRMATION', False): rec.active = 1 user.save(rec, commit=True) # log the user in setUserStatus(rec.email, rec.id) if rec.active == 1: success = "active" else: success = "waiting" #inform the admins inform_admin_of_registration(rec) return render_template('registration_success.html', success=success, next=next) else: flash("That registration request has expired") return redirect('/') if request.form: #update the record user.update(rec, request.form) if validForm(rec): rec.active = 0 # Self registered accounts are inactive by default set_password_from_form(rec) set_username_from_form(rec) rec.access_token = get_access_token() rec.access_token_expires = time() + (3600 * 48) if site_config.get('AUTOMATICALLY_ACTIVATE_NEW_USERS', False): rec.active = 1 success = "active" try: user.save(rec) # give user default roles for role in site_config.get('DEFAULT_USER_ROLES', ['user']): User(g.db).add_role(rec.id, role) g.db.commit() # log the user in setUserStatus(rec.email, rec.id) #inform the admins inform_admin_of_registration(rec) #Send confirmation email to user if not already active full_name = '{} {}'.format(rec.first_name, rec.last_name).strip() to = [(full_name, rec.email)] context = {'rec': rec, 'confirmation_code': rec.access_token} subject = 'Please confirm your account registration at {}'.format( site_config['SITE_NAME']) html_template = 'email/registration_confirm.html' text_template = 'email/registration_confirm.txt' if rec.active == 1: subject = 'Your account is now active at {}'.format( site_config['SITE_NAME']) html_template = 'email/activation_complete.html' text_template = 'email/activation_complete.txt' send_message(to, context=context, subject=subject, html_template=html_template, text_template=text_template) except Exception as e: g.db.rollback() mes = "An error occured while new user was attempting to register" printException(mes, "error", e) # Send email to the administrator to = [(site_config['MAIL_DEFAULT_SENDER'], site_config['MAIL_DEFAULT_ADDR'])] context = {'mes': mes, 'rec': rec, 'e': str(e)} body = "Signup Error\n{{context.mes}}\n{{context.e}}\nrec:\n{{context.rec}}" send_message(to, context=context, body=body, subject=mes) success = False return render_template( 'registration_success.html', success=success, next=next, ) return render_template( 'user_edit.html', rec=rec, no_delete=no_delete, is_admin=is_admin, next=next, )
def edit(rec_handle=None): setExits() g.title = "Edit {} Record".format(g.title) #import pdb;pdb.set_trace() site_config = get_site_config() user = User(g.db) rec = None request_rec_id = cleanRecordID( request.form.get('id', request.args.get('id', -1))) is_admin = g.admin.has_access(g.user, User) no_delete = not is_admin new_password = '' confirm_password = '' user_roles = ['user'] # default #limit roles to roles <= current users rank curr_user_max_rank = user.max_role_rank(g.user) roles = Role(g.db).select(where="rank <= {}".format(curr_user_max_rank)) include_inactive = True next = request.form.get('next', request.args.get('next', '')) if not is_admin: g.listURL = g.homeURL # Non admins can't see the list include_inactive = False if rec_handle != None: pass #rec_handle has to come from admin() at this point elif rec_handle == None and g.user != None and request_rec_id == -1: rec_handle = g.user else: rec_handle = request_rec_id if rec_handle < 0: flash("That is not a valid User ID") return redirect(g.listURL) if not request.form: """ if no form object, send the form page """ if rec_handle != g.user and not is_admin: flash("You do not have access to that area") return redirect(g.homeURL) elif curr_user_max_rank < user.max_role_rank(rec_handle): flash( "You don't have sufficiant privelages to edit that user record." ) return redirect(g.homeURL) elif rec_handle == 0: rec = user.new() else: rec = user.get(rec_handle, include_inactive=include_inactive) if not rec: flash("Unable to locate user record") return redirect('/') user_roles = get_user_role_names(rec) else: #have the request form # import pdb;pdb.set_trace() is_new_user = False if rec_handle and request.form['id'] != 'None': rec = user.get(rec_handle, include_inactive=include_inactive) user_roles = get_user_role_names(rec) else: # its a new unsaved record is_new_user = True rec = user.new() user.update(rec, request.form) if validForm(rec): #Are we editing the current user's record? editingCurrentUser = '' if (g.user == rec.username): if 'new_username' in request.form: editingCurrentUser = request.form['new_username'].strip() else: editingCurrentUser = g.user else: if (g.user == rec.email): editingCurrentUser = request.form['email'].strip() #update the record user.update(rec, request.form) # ensure these are ints if 'may_send_email' in rec._fields: rec.may_send_email = cleanRecordID(rec.may_send_email) if 'may_send_text' in rec._fields: rec.may_send_text = cleanRecordID(rec.may_send_text) set_username_from_form(rec) set_password_from_form(rec) try: user.save(rec) # update the user roles if 'roles_select' in request.form: # import pdb;pdb.set_trace() #delete all the users current roles user.clear_roles(rec.id) for role_name in request.form.getlist('roles_select'): #find the role by name role = Role(g.db).select_one( where='name = "{}"'.format(role_name)) if role: user.add_role(rec.id, role.id) # if the username or email address are the same as g.user # update g.user if it changes if (editingCurrentUser != ''): setUserStatus(editingCurrentUser, rec.id) g.db.commit() except Exception as e: g.db.rollback() flash( printException( 'Error attempting to save ' + g.title + ' record.', "error", e)) return redirect(g.listURL) if is_new_user: rec.access_token = get_access_token() rec.access_token_expires = time() + (3600 * 48) #inform the admins inform_admin_of_registration(rec) # send an email to welcome the new user full_name = '{} {}'.format(rec.first_name, rec.last_name).strip() context = { 'rec': rec, 'full_name': full_name, } to_address_list = [(full_name, rec.email)] sent, msg = send_message( to_address_list, subject="Welcome to {{ site_config.SITE_NAME}}", context=context, html_template='email/welcome.html', text_template='email/welcome.txt', ) if not sent: flash('The welcome message could not be sent. Error: {}'. format(msg)) return redirect(g.listURL) else: # form did not validate, give user the option to keep their old password if there was one #need to restore the username user.update(rec, request.form) if 'new_username' in request.form: rec.username = request.form[ 'new_username'] #preserve user input # preserve the selected roles #import pdb;pdb.set_trace() if 'roles_select' in request.form: user_roles = request.form.getlist('roles_select') #and password new_password = request.form.get('new_password', '') confirm_password = request.form.get('confirm_password', '') # display form return render_template( 'user_edit.html', rec=rec, no_delete=no_delete, is_admin=is_admin, next=next, user_roles=user_roles, roles=roles, new_password=new_password, confirm_password=confirm_password, )
def edit(rec_id=None): setExits() g.title = "Edit {} Record".format(g.title) role = PRIMARY_TABLE(g.db) rec = None super_user = User(g.db).user_has_role(session['user_id'], 'Super') no_delete = False rec_id = cleanRecordID(request.form.get('id', rec_id)) if rec_id < 0: flash("That is not a valid ID") return redirect(g.listURL) if not request.form: """ if no form object, send the form page """ if rec_id == 0: rec = role.new() else: rec = role.get(rec_id) if not rec: flash("Unable to locate that record") return redirect(g.listURL) else: #have the request form if rec_id and request.form['id'] != 'None': rec = role.get(rec_id) else: # its a new unsaved record # import pdb;pdb.set_trace() rec = role.new() role.update(rec, request.form) if validForm(rec): #update the record # import pdb;pdb.set_trace() # set default for locked rec.locked = 0 role.update(rec, request.form) if request.form.get('locked'): rec.locked = 1 try: role.save(rec) g.db.commit() except Exception as e: g.db.rollback() flash( printException( 'Error attempting to save ' + g.title + ' record.', "error", e)) return redirect(g.listURL) else: # form did not validate pass if rec and rec.locked and not super_user: no_delete = True # display form return render_template('role_edit.html', rec=rec, super_user=super_user, no_delete=no_delete)
def test_user_get(): import shotglass2.users.views.password as login from shotglass2.users.models import User #do some tests... user = User(db) rec = user.get(1) assert rec.username == 'admin' rec = user.get('admin') assert rec.username == 'admin' admin_roles = user.get_roles(rec.id) assert admin_roles != None assert len(admin_roles)>0 assert admin_roles[0].name == "super" assert user.max_role_rank(1) == 1000; assert user.max_role_rank('admin') == 1000; # test that user admin is in admins assert user.is_admin('admin') assert user.is_admin(rec.id) #user John is not administrator rec = user.get('John') assert user.is_admin(rec.id) == False recs = user.select() assert len(recs) == 3 # select inactive users too... recs = user.select(include_inactive=True) assert len(recs) == 4 #ensure that inactive users are not returned with get rec = user.get('none') assert rec == None #and now we can... rec = user.get('none',include_inactive=True) assert rec.username == 'none' # user 'none' has no roles assert user.get_roles(rec.id) == None #add some roles for none user.add_role(rec.id,'user') assert user.get_roles(rec.id) != None #ensure that username is case sensitive rec = user.get('doris') assert rec.username == 'doris' rec = user.get('Doris') assert rec == None #get by email and NOT case sensitive rec = user.get('*****@*****.**') assert rec.last_name == "Goodman" rec = user.get('*****@*****.**') assert rec.last_name == "Goodman" #and that spaces are stripped rec = user.get(' [email protected] ') assert rec.last_name == "Goodman" #test a total miss assert user.get('something that doesnt exist') == None assert user.get(234343) == None