def createUserWithPassword(email, password, bcrypt, permission=1, cgac_code="SYS"): """Convenience function to set up fully-baked user (used for setup/testing only).""" sess = GlobalDB.db().session status = sess.query(UserStatus).filter(UserStatus.name == 'approved').one() user = User(email=email, user_status=status, permission_type_id=permission, cgac_code=cgac_code, name='Administrator', title='System Admin') user.salt, user.password_hash = getPasswordHash(password, bcrypt) sess.add(user) sess.commit() return user
def create_user_with_password(email, password, bcrypt, website_admin=False): """Convenience function to set up fully-baked user (used for setup/testing only).""" sess = GlobalDB.db().session user = User(email=email, name='Administrator', title='System Admin', website_admin=website_admin) user.salt, user.password_hash = get_password_hash(password, bcrypt) sess.add(user) sess.commit() return user
def create_user_with_password(email, password, bcrypt, website_admin=False): """Convenience function to set up fully-baked user (used for setup/testing only).""" sess = GlobalDB.db().session user = User( email=email, name='Administrator', title='System Admin', website_admin=website_admin ) user.salt, user.password_hash = get_password_hash(password, bcrypt) sess.add(user) sess.commit() return user
def create_email_confirmation(self,system_email): """ Creates user record and email arguments: system_email -- (string) email used to send messages """ sess = GlobalDB.db().session request_fields = RequestDictionary.derive(self.request) try: if 'email' not in request_fields: raise ResponseException( "Request body must include email", StatusCode.CLIENT_ERROR) email = request_fields['email'] if not re.match("[^@]+@[^@]+\.[^@]+",email): raise ValueError("Invalid Email Format") except (ResponseException, ValueError) as exc: return JsonResponse.error(exc, StatusCode.CLIENT_ERROR) try : user = sess.query(User).filter( func.lower(User.email) == func.lower(request_fields['email']) ).one() except NoResultFound: # Create user with specified email if none is found user = User(email=email) user.user_status_id = USER_STATUS_DICT["awaiting_confirmation"] user.permissions = 0 sess.add(user) sess.commit() else: try: good_statuses = (USER_STATUS_DICT["awaiting_confirmation"], USER_STATUS_DICT["email_confirmed"]) if user.user_status_id not in good_statuses: raise ResponseException( "User already registered", StatusCode.CLIENT_ERROR) except ResponseException as exc: return JsonResponse.error(exc, exc.status) email_token = sesEmail.createToken(email, "validate_email") link= "".join([AccountHandler.FRONT_END,'#/registration/',email_token]) email_template = {'[USER]': email, '[URL]':link} new_email = sesEmail(email, system_email,templateType="validate_email",parameters=email_template) new_email.send() return JsonResponse.create(StatusCode.OK,{"message":"Email Sent"})
def createUser(self, username): """ Creates a new entry for new usernames, if a user is found with this email that has not yet registered, just returns that user's ID. Raises an exception if multiple results found, or if user has already registered. Arguments: username - username to find or create an id for Returns: user object """ # Check if user exists queryResult = self.session.query(User).options(joinedload("user_status")).filter(User.username == username).all() if(len(queryResult) == 1): # If so, check their status user = queryResult[0] if(user.user_status.name == "awaiting_confirmation" or user.user_status.name == "email_confirmed"): # User has not yet registered, may restart process return user elif(len(queryResult) == 0): # If not, add new user newUser = User(username = username) self.session.add(newUser) self.session.commit() return newUser else: # Multiple entries for this user, server error raise MultipleResultsFound("Multiple entries for single username")
def createUserWithPassword(self,email,password,bcrypt,permission=1,cgac_code="SYS"): """ This directly creates a valid user in the database with password and permissions set. Not used during normal behavior of the app, but useful for configuration and testing. Arguments: email - Email for new user password - Password to assign to user bcrypt - bcrypt to use for password hashing admin - Whether the new user should be an admin """ user = User(email = email) self.session.add(user) self.setPassword(user,password,bcrypt) self.changeStatus(user,"approved") self.setPermission(user,permission) user.cgac_code = cgac_code self.session.commit()
def addUnconfirmedEmail(self,email): """ Create user with specified email Arguments: email - Add user with specified email """ user = User(email = email) self.changeStatus(user,"awaiting_confirmation") self.setPermission(user,0) # Users start with no permissions self.session.add(user) self.session.commit()
def setUpClass(cls): """Set up class-wide resources like users.""" super(DomainTests, cls).setUpClass() with create_app().app_context(): sess = GlobalDB.db().session user = User() r_cgac = CGACFactory() w_cgac = CGACFactory() s_frec_cgac = CGACFactory() s_frec = FRECFactory(cgac=s_frec_cgac) e_frec_cgac = CGACFactory() e_frec = FRECFactory(cgac=e_frec_cgac) f_cgac = CGACFactory() user.affiliations = [ UserAffiliation(cgac=r_cgac, frec=None, permission_type_id=PERMISSION_SHORT_DICT['r']), UserAffiliation(cgac=w_cgac, frec=None, permission_type_id=PERMISSION_SHORT_DICT['w']), UserAffiliation(cgac=None, frec=s_frec, permission_type_id=PERMISSION_SHORT_DICT['s']), UserAffiliation(cgac=None, frec=e_frec, permission_type_id=PERMISSION_SHORT_DICT['e']), UserAffiliation(cgac=f_cgac, frec=None, permission_type_id=PERMISSION_SHORT_DICT['f']) ] sess.add_all([ r_cgac, w_cgac, s_frec_cgac, s_frec, e_frec_cgac, e_frec, f_cgac ]) sess.commit()
def setUpClass(cls): """Set up resources to be shared within a test class""" cls.session_id = "" with createValidatorApp().app_context(): # update application's db config options so unittests # run against test databases suite = cls.__name__.lower() config = dataactcore.config.CONFIG_DB cls.num = randint(1, 9999) config['db_name'] = 'unittest{}_{}_data_broker'.format( cls.num, suite) dataactcore.config.CONFIG_DB = config createDatabase(CONFIG_DB['db_name']) runMigrations() # drop and re-create test user db/tables setupUserDB() # drop and re-create test job db/tables setupJobTrackerDB() # drop and re-create test error db/tables setupErrorDB() # drop and re-create test validation db/tables setupValidationDB() # load e-mail templates setupEmails() # set up default e-mails for tests test_users = {} test_users['admin_email'] = '*****@*****.**' test_users['change_user_email'] = '*****@*****.**' test_users['password_reset_email'] = '*****@*****.**' test_users['inactive_email'] = '*****@*****.**' test_users['password_lock_email'] = '*****@*****.**' test_users['expired_lock_email'] = '*****@*****.**' test_users['agency_admin_email'] = '*****@*****.**' # this email is for a regular agency_user email that is to be used for # testing functionality expected by a normal, base user test_users['agency_user'] = '******' test_users['approved_email'] = '*****@*****.**' test_users['submission_email'] = '*****@*****.**' user_password = '******' admin_password = '******' # set up users for status tests StatusTestUser = namedtuple( 'StatusTestUser', ['email', 'user_status', 'permissions', 'user_type']) StatusTestUser.__new__.__defaults__ = (None, None, AccountType.AGENCY_USER, None) status_test_users = [] status_test_users.append( StatusTestUser('*****@*****.**', 'awaiting_confirmation', 0)) status_test_users.append( StatusTestUser('*****@*****.**', 'email_confirmed')) status_test_users.append( StatusTestUser('*****@*****.**', 'awaiting_approval')) status_test_users.append( StatusTestUser('*****@*****.**', 'awaiting_approval')) status_test_users.append( StatusTestUser('*****@*****.**', 'awaiting_approval')) status_test_users.append( StatusTestUser( test_users['admin_email'], 'approved', AccountType.WEBSITE_ADMIN + AccountType.AGENCY_USER)) status_test_users.append( StatusTestUser(test_users['approved_email'], 'approved')) status_test_users.append( StatusTestUser('*****@*****.**', 'denied')) # add new users createUserWithPassword(test_users["submission_email"], user_password, Bcrypt()) createUserWithPassword(test_users["change_user_email"], user_password, Bcrypt()) createUserWithPassword(test_users["password_reset_email"], user_password, Bcrypt()) createUserWithPassword(test_users["inactive_email"], user_password, Bcrypt()) createUserWithPassword(test_users["password_lock_email"], user_password, Bcrypt()) createUserWithPassword(test_users['expired_lock_email'], user_password, Bcrypt()) createUserWithPassword(test_users['agency_admin_email'], admin_password, Bcrypt(), permission=4) createUserWithPassword(test_users['agency_user'], user_password, Bcrypt()) # get user info and save as class variables for use by tests sess = GlobalDB.db().session agencyUser = sess.query(User).filter( User.email == test_users['agency_user']).one() cls.agency_user_id = agencyUser.user_id # set the specified account to be expired expiredUser = sess.query(User).filter( User.email == test_users['expired_lock_email']).one() today = parse(time.strftime("%c")) expiredUser.last_login_date = (today - timedelta(days=120)).strftime("%c") sess.add(expiredUser) # create users for status testing for u in status_test_users: user = User(email=u.email, permissions=u.permissions, user_status=sess.query(UserStatus).filter( UserStatus.name == u.user_status).one()) sess.add(user) # set up approved user user = sess.query(User).filter( User.email == test_users['approved_email']).one() user.username = "******" user.cgac_code = "000" user.salt, user.password_hash = getPasswordHash( user_password, Bcrypt()) sess.add(user) cls.approved_user_id = user.user_id # set up admin user admin = sess.query(User).filter( User.email == test_users['admin_email']).one() admin.salt, admin.password_hash = getPasswordHash( admin_password, Bcrypt()) admin.name = "Mr. Manager" admin.cgac_code = "SYS" sess.add(admin) # set up status changed user statusChangedUser = sess.query(User).filter( User.email == test_users['change_user_email']).one() statusChangedUser.name = "Test User" statusChangedUser.user_status = sess.query(UserStatus).filter( UserStatus.name == 'email_confirmed').one() sess.add(statusChangedUser) cls.status_change_user_id = statusChangedUser.user_id # set up deactivated user deactivated_user = sess.query(User).filter( User.email == test_users['inactive_email']).one() deactivated_user.last_login_date = time.strftime("%c") deactivated_user.is_active = False sess.add(deactivated_user) sess.commit() # get lookup dictionaries cls.jobStatusDict = lookups.JOB_STATUS_DICT cls.jobTypeDict = lookups.JOB_TYPE_DICT cls.fileTypeDict = lookups.FILE_TYPE_DICT cls.fileStatusDict = lookups.FILE_STATUS_DICT cls.ruleSeverityDict = lookups.RULE_SEVERITY_DICT cls.errorTypeDict = lookups.ERROR_TYPE_DICT cls.publishStatusDict = lookups.PUBLISH_STATUS_DICT cls.userStatusDict = lookups.USER_STATUS_DICT # set up info needed by the individual test classes cls.test_users = test_users cls.user_password = user_password cls.admin_password = admin_password cls.local = CONFIG_BROKER['local']
def max_login(self, session): """ Logs a user in if their password matches using MAX Args: session: Session object from flask Returns: A JsonResponse containing the user information or details on which error occurred, such as whether a type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a different, unexpected error occurred. """ try: safe_dictionary = RequestDictionary(self.request) ticket = safe_dictionary.get_value("ticket") service = safe_dictionary.get_value('service') # Call MAX's serviceValidate endpoint and retrieve the response max_dict = get_max_dict(ticket, service) if 'cas:authenticationSuccess' not in max_dict[ 'cas:serviceResponse']: raise ValueError( "The Max CAS endpoint was unable to locate your session " "using the ticket/service combination you provided.") cas_attrs = max_dict['cas:serviceResponse'][ 'cas:authenticationSuccess']['cas:attributes'] # Grab MAX ID to see if a service account is being logged in max_id_components = cas_attrs['maxAttribute:MAX-ID'].split('_') service_account_flag = (len(max_id_components) > 1 and max_id_components[0].lower() == 's') # Grab the email and list of groups from MAX's response email = cas_attrs['maxAttribute:Email-Address'] try: sess = GlobalDB.db().session user = sess.query(User).filter( func.lower(User.email) == func.lower(email)).one_or_none() # If the user does not exist, create them since they are allowed to access the site because they got # past the above group membership checks if user is None: user = User() user.email = email set_user_name(user, cas_attrs) set_max_perms(user, cas_attrs['maxAttribute:GroupList'], service_account_flag) sess.add(user) sess.commit() except MultipleResultsFound: raise ValueError("An error occurred during login.") return self.create_session_and_response(session, user) # Catch any specifically raised errors or any other errors that may have happened and return them cleanly. # We add the error parameter here because this endpoint needs to provide better feedback, and to avoid changing # the default behavior of the JsonResponse class globally. except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR, error=str(e)) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED, error=str(e)) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR, error=str(e))
def max_login(self, session): """ Logs a user in if their password matches using MAX Args: session: Session object from flask Returns: A JsonResponse containing the user information or details on which error occurred, such as whether a type was wrong, something wasn't implemented, invalid keys were provided, login was denied, or a different, unexpected error occurred. """ try: safe_dictionary = RequestDictionary(self.request) ticket = safe_dictionary.get_value("ticket") service = safe_dictionary.get_value('service') # Call MAX's serviceValidate endpoint and retrieve the response max_dict = get_max_dict(ticket, service) if 'cas:authenticationSuccess' not in max_dict['cas:serviceResponse']: raise ValueError("The Max CAS endpoint was unable to locate your session " "using the ticket/service combination you provided.") cas_attrs = max_dict['cas:serviceResponse']['cas:authenticationSuccess']['cas:attributes'] # Grab MAX ID to see if a service account is being logged in max_id_components = cas_attrs['maxAttribute:MAX-ID'].split('_') service_account_flag = (len(max_id_components) > 1 and max_id_components[0].lower() == 's') # Grab the email and list of groups from MAX's response email = cas_attrs['maxAttribute:Email-Address'] try: sess = GlobalDB.db().session user = sess.query(User).filter(func.lower(User.email) == func.lower(email)).one_or_none() # If the user does not exist, create them since they are allowed to access the site because they got # past the above group membership checks if user is None: user = User() user.email = email set_user_name(user, cas_attrs) set_max_perms(user, cas_attrs['maxAttribute:GroupList'], service_account_flag) sess.add(user) sess.commit() except MultipleResultsFound: raise ValueError("An error occurred during login.") return self.create_session_and_response(session, user) # Catch any specifically raised errors or any other errors that may have happened and return them cleanly. # We add the error parameter here because this endpoint needs to provide better feedback, and to avoid changing # the default behavior of the JsonResponse class globally. except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR, error=str(e)) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED, error=str(e)) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR, error=str(e))
def max_login(self,session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the reponse object """ try: safeDictionary = RequestDictionary(self.request) # Obtain POST content ticket = safeDictionary.getValue("ticket") service = safeDictionary.getValue('service') parent_group = CONFIG_BROKER['parent_group'] # Call MAX's serviceValidate endpoint and retrieve the response max_dict = self.get_max_dict(ticket, service) if not 'cas:authenticationSuccess' in max_dict['cas:serviceResponse']: raise ValueError("You have failed to login successfully with MAX") # Grab the email and list of groups from MAX's response email = max_dict['cas:serviceResponse']['cas:authenticationSuccess']['cas:attributes']['maxAttribute:Email-Address'] group_list_all = max_dict['cas:serviceResponse']['cas:authenticationSuccess']['cas:attributes']['maxAttribute:GroupList'].split(',') group_list = [g for g in group_list_all if g.startswith(parent_group)] cgac_group = [g for g in group_list if g.startswith(parent_group+"-CGAC_")] # Deny access if they are not aligned with an agency if not cgac_group: raise ValueError("You have logged in with MAX but do not have permission to access the broker.") try: sess = GlobalDB.db().session user = sess.query(User).filter(func.lower(User.email) == func.lower(email)).one_or_none() # If the user does not exist, create them since they are allowed to access the site because they got # past the above group membership checks if user is None: user = User() first_name = max_dict["cas:serviceResponse"]['cas:authenticationSuccess']['cas:attributes'][ 'maxAttribute:First-Name'] middle_name = max_dict["cas:serviceResponse"]['cas:authenticationSuccess']['cas:attributes'][ 'maxAttribute:Middle-Name'] last_name = max_dict["cas:serviceResponse"]['cas:authenticationSuccess']['cas:attributes'][ 'maxAttribute:Last-Name'] user.email = email # Check for None first so the condition can short-circuit without # having to worry about calling strip() on a None object if middle_name is None or middle_name.strip() == '': user.name = first_name + " " + last_name else: user.name = first_name + " " + middle_name[0] + ". " + last_name user.user_status_id = user.user_status_id = USER_STATUS_DICT['approved'] sess.add(user) sess.commit() # update user's cgac based on their current membership # If part of the SYS agency, use that as the cgac otherwise use the first agency provided if [g for g in cgac_group if g.endswith("SYS")]: user.cgac_code = "SYS" else: user.cgac_code = cgac_group[0][-3:] self.grant_highest_permission(sess, user, group_list, cgac_group[0]) except MultipleResultsFound: raise ValueError("An error occurred during login.") return self.create_session_and_response(session, user) except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e,StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e,StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e,StatusCode.INTERNAL_ERROR) return self.response
def max_login(self, session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the response object """ try: safe_dictionary = RequestDictionary(self.request) # Obtain POST content ticket = safe_dictionary.get_value("ticket") service = safe_dictionary.get_value('service') # Call MAX's serviceValidate endpoint and retrieve the response max_dict = get_max_dict(ticket, service) if 'cas:authenticationSuccess' not in max_dict['cas:serviceResponse']: raise ValueError("You have failed to login successfully with MAX") cas_attrs = max_dict['cas:serviceResponse']['cas:authenticationSuccess']['cas:attributes'] # Grab the email and list of groups from MAX's response email = cas_attrs['maxAttribute:Email-Address'] try: sess = GlobalDB.db().session user = sess.query(User).filter(func.lower(User.email) == func.lower(email)).one_or_none() # If the user does not exist, create them since they are allowed to access the site because they got # past the above group membership checks if user is None: user = User() first_name = cas_attrs['maxAttribute:First-Name'] middle_name = cas_attrs['maxAttribute:Middle-Name'] last_name = cas_attrs['maxAttribute:Last-Name'] user.email = email # Check for None first so the condition can short-circuit without # having to worry about calling strip() on a None object if middle_name is None or middle_name.strip() == '': user.name = first_name + " " + last_name else: user.name = first_name + " " + middle_name[0] + ". " + last_name set_max_perms(user, cas_attrs['maxAttribute:GroupList']) sess.add(user) sess.commit() except MultipleResultsFound: raise ValueError("An error occurred during login.") return self.create_session_and_response(session, user) except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)
def max_login(self, session): """ Logs a user in if their password matches arguments: session -- (Session) object from flask return the response object """ try: safe_dictionary = RequestDictionary(self.request) # Obtain POST content ticket = safe_dictionary.get_value("ticket") service = safe_dictionary.get_value('service') # Call MAX's serviceValidate endpoint and retrieve the response max_dict = get_max_dict(ticket, service) if 'cas:authenticationSuccess' not in max_dict[ 'cas:serviceResponse']: raise ValueError( "You have failed to login successfully with MAX") cas_attrs = max_dict['cas:serviceResponse'][ 'cas:authenticationSuccess']['cas:attributes'] # Grab the email and list of groups from MAX's response email = cas_attrs['maxAttribute:Email-Address'] try: sess = GlobalDB.db().session user = sess.query(User).filter( func.lower(User.email) == func.lower(email)).one_or_none() # If the user does not exist, create them since they are allowed to access the site because they got # past the above group membership checks if user is None: user = User() first_name = cas_attrs['maxAttribute:First-Name'] middle_name = cas_attrs['maxAttribute:Middle-Name'] last_name = cas_attrs['maxAttribute:Last-Name'] user.email = email # Check for None first so the condition can short-circuit without # having to worry about calling strip() on a None object if middle_name is None or middle_name.strip() == '': user.name = first_name + " " + last_name else: user.name = first_name + " " + middle_name[ 0] + ". " + last_name set_max_perms(user, cas_attrs['maxAttribute:GroupList']) sess.add(user) sess.commit() except MultipleResultsFound: raise ValueError("An error occurred during login.") return self.create_session_and_response(session, user) except (TypeError, KeyError, NotImplementedError) as e: # Return a 400 with appropriate message return JsonResponse.error(e, StatusCode.CLIENT_ERROR) except ValueError as e: # Return a 401 for login denied return JsonResponse.error(e, StatusCode.LOGIN_REQUIRED) except Exception as e: # Return 500 return JsonResponse.error(e, StatusCode.INTERNAL_ERROR)