def setup(self, researcher=True, apikey=True, study=True): """ This function is used to initialize that database for each test. This was written in this fashion because of a known issue with the HybridTest class that does not consistently use database changes that persist between tests """ if apikey and not researcher: raise Exception("invalid setup criteria") if researcher: self.researcher = Researcher.create_with_password( username=TEST_USERNAME, password=TEST_PASSWORD) if apikey: self.api_key = ApiKey.generate(self.researcher, has_tableau_api_permissions=True) self.api_key_public = self.api_key.access_key_id self.api_key_private = self.api_key.access_key_secret_plaintext if study: self.study = Study.create_with_object_id( device_settings=DeviceSettings(), encryption_key=TEST_STUDY_ENCRYPTION_KEY, name=TEST_STUDY_NAME, ) if researcher: self.study_relation = StudyRelation( study=self.study, researcher=self.researcher, relationship="researcher", ).save()
def edit_study(study_id=None): # get the data points for display for all researchers in this study query = Researcher.filter_alphabetical(study_relations__study_id=study_id).values_list( "id", "username", "study_relations__relationship", "site_admin" ) # transform raw query data as needed listed_researchers = [] for pk, username, relationship, site_admin in query: listed_researchers.append(( pk, username, "Site Admin" if site_admin else relationship.replace("_", " ").title(), site_admin )) return render_template( 'edit_study.html', study=Study.objects.get(pk=study_id), administerable_researchers=get_administerable_researchers(), allowed_studies=get_researcher_allowed_studies(), listed_researchers=listed_researchers, is_admin=researcher_is_an_admin(), redirect_url='/edit_study/{:s}'.format(study_id), session_researcher=get_session_researcher(), )
def refresh_data_access_credentials(freq, ssm_client=None, webserver=False): """ Refresh the data access credentials for a particular BATCH USER user and upload them (encrypted) to the AWS Parameter Store. This enables AWS batch jobs to get the credentials and thereby access the data access API (DAA). :param freq: string, one of 'hourly' | 'daily' | 'weekly' | 'monthly' | 'manually' This is used to know what call the data access credentials on AWS. """ # Get or create Researcher with no password. This means that nobody can log in as this # Researcher in the web interface. researcher_name = 'BATCH USER {}'.format(freq) mock_researchers = Researcher.objects.filter(username=researcher_name) if not mock_researchers.exists(): mock_researcher = Researcher.create_without_password(researcher_name) else: mock_researcher = mock_researchers.get() mock_researcher.save() # Ensure that the Researcher is attached to all Studies. This allows them to access all # data via the DAA. for study in Study.objects.all(): StudyRelation.objects.get_or_create( study=study, researcher=mock_researcher, relationship=ResearcherRole.researcher, is_batch_user=True, ) # Reset the credentials. This ensures that they aren't stale. access_key, secret_key = mock_researcher.reset_access_credentials() if not webserver: generic_config = get_generic_config() else: generic_config = get_eb_config() # Append the frequency to the SSM (AWS Systems Manager) names. This ensures that the # different frequency jobs' keys do not overwrite each other. access_key_ssm_name = '{}-{}'.format(generic_config['access_key_ssm_name'], freq) secret_key_ssm_name = '{}-{}'.format(generic_config['secret_key_ssm_name'], freq) # Put the credentials (encrypted) into AWS Parameter Store if not ssm_client: ssm_client = get_boto_client('ssm') ssm_client.put_parameter( Name=access_key_ssm_name, Value=access_key, Type='SecureString', Overwrite=True, ) ssm_client.put_parameter( Name=secret_key_ssm_name, Value=secret_key, Type='SecureString', Overwrite=True, )
def get_administerable_researchers(): """ Site admins see all researchers, study admins see researchers on their studies. """ researcher_admin = get_session_researcher() if researcher_admin.site_admin: relevant_researchers = Researcher.get_all_researchers_by_username() else: relevant_researchers = researcher_admin.get_administered_researchers_by_username() return relevant_researchers
def migrate_admins(): d_admin_list = [] # Build all Researchers for m_admin in MAdminSet.iterator(): with error_handler: d_admin = DAdmin( username=m_admin['_id'], admin=m_admin['system_admin'], access_key_id=m_admin['access_key_id'] or None, # access_key_id is unique and therefore nullable access_key_secret=m_admin['access_key_secret'] or '', access_key_secret_salt=m_admin['access_key_secret_salt'] or '', password=m_admin['password'] or 'NoPassword', salt=m_admin['salt'], deleted=False, ) # Validate the Researcher and add it to the bulk_create list d_admin.full_clean() d_admin_list.append(d_admin) # Bulk_create the list of Researchers DAdmin.objects.bulk_create(d_admin_list) # Now that the Researchers have primary keys, fill in the Study-Researcher ManyToMany relationship # Create a mapping from Researcher's username to primary key admin_username_to_pk_dict = dict(DAdmin.objects.values_list('username', 'pk')) d_study_admin_relation_list = [] for study_id, admin_username in d_study_admin_list: with error_handler: try: admin_id = admin_username_to_pk_dict[admin_username] except KeyError: # study_name = DStudy.objects.get(pk=study_id).name print('Admin {} is referenced by a Study but does not exist.'.format(admin_username)) continue # Populate a list of database objects in the Study-Researcher relationship table new_relation = DAdmin.studies.through(study_id=study_id, researcher_id=admin_id) d_study_admin_relation_list.append(new_relation) # Bulk_create the Study-Researcher relationship objects with error_handler: DAdmin.studies.through.objects.bulk_create(d_study_admin_relation_list)
def edit_study(study_id=None): study = Study.objects.get(pk=study_id) all_researchers = Researcher.get_all_researchers_by_username() return render_template( 'edit_study.html', study=study, all_researchers=all_researchers, allowed_studies=get_admins_allowed_studies(), system_admin=admin_is_system_admin(), redirect_url='/edit_study/{:s}'.format(study_id), )
def login(): """ Authenticates administrator login, redirects to login page if authentication fails. """ if request.method == 'POST': username = request.values["username"] password = request.values["password"] if Researcher.check_password(username, password): admin_authentication.log_in_admin(username) return redirect("/choose_study") else: flash("Incorrect username & password combination; try again.", 'danger') return redirect("/")
def manage_researchers(): researcher_list = [] for researcher in Researcher.get_all_researchers_by_username(): allowed_studies = Study.get_all_studies_by_name().filter(researchers=researcher).values_list('name', flat=True) researcher_list.append((researcher.as_native_python(), list(allowed_studies))) return render_template( 'manage_researchers.html', admins=json.dumps(researcher_list), allowed_studies=get_admins_allowed_studies(), system_admin=admin_is_system_admin() )
def reset_admin_password(): username = session['admin_username'] current_password = request.values['current_password'] new_password = request.values['new_password'] confirm_new_password = request.values['confirm_new_password'] if not Researcher.check_password(username, current_password): flash("The Current Password you have entered is invalid", 'danger') return redirect('/manage_credentials') if not check_password_requirements(new_password, flash_message=True): return redirect("/manage_credentials") if new_password != confirm_new_password: flash("New Password does not match Confirm New Password", 'danger') return redirect('/manage_credentials') Researcher.objects.get(username=username).set_password(new_password) flash("Your password has been reset!", 'success') return redirect('/manage_credentials')
def create_new_researcher(): if request.method == 'GET': return render_template('create_new_researcher.html') # Drop any whitespace or special characters from the username username = ''.join(e for e in request.form.get('admin_id', '') if e.isalnum()) password = request.form.get('password', '') if Researcher.objects.filter(username=username).exists(): flash(f"There is already a researcher with username {username}", 'danger') return redirect('/create_new_researcher') else: researcher = Researcher.create_with_password(username, password) return redirect('/edit_researcher/{:d}'.format(researcher.pk))
def test_all_routes(self): """ Tests urls """ app2 = subdomain("frontend") app2.register_blueprint(admin_pages.admin_pages) long_encryption_key = 'aabbccddefggiijjkklmnoppqqrrsstt' researcher = Researcher.create_with_password('test_user', 'test_password') researcher.admin = True researcher.reset_access_credentials() researcher.save() study = Study.create_with_object_id(name='test_study', encryption_key=long_encryption_key) researcher.studies.add(study) self.selenium.get("localhost:54321") self.selenium.find_element_by_name('username').send_keys('test_user') self.selenium.find_element_by_name('password').send_keys( 'test_password') self.selenium.find_element_by_name('submit').click() for rule in app2.url_map.iter_rules(): str_rule = str(rule) self.assertIn(str_rule, ADMIN_PAGES) if ADMIN_PAGES[str_rule]['method'] == 'get': self.selenium.get("localhost:54321" + str_rule) elif ADMIN_PAGES[str_rule]['method'] == 'post': continue elif ADMIN_PAGES[str_rule]['method'] == 'get_param': str_rule_formatted = re.sub(r"<\w+:\w+>", str(study.id), str_rule) self.selenium.get("localhost:54321" + str_rule_formatted) else: continue response = self.determine_errors() self.assertEqual(response, '200')
def handle(self, *args, **options): new_researcher = Researcher.create_with_password("admin", "admin") new_researcher.elevate_to_site_admin()
def test_researcher_mongo_integrity(self): researcher = Researcher(**self.translated_reference_researcher) x = compare_dictionaries(self.translated_reference_researcher, researcher.as_unpacked_native_python(), ignore=["deleted", "id"]) self.assertTrue(x)
from sys import path path.insert(0, abspath(__file__).rsplit('/', 2)[0]) import itertools import requests from config.constants import ResearcherRole from pprint import pprint from data_access_api_reference import download_data from database.study_models import Study from database.user_models import Researcher, StudyRelation try: test_user = Researcher.objects.get(username="******") except Researcher.DoesNotExist: test_user = Researcher.create_without_password("test_user") download_data.API_URL_BASE = "http://127.0.0.1:8080/" debugging_study = Study.objects.get(name='debugging study') download_data.RUNNING_IN_TEST_MODE = True download_data.SKIP_DOWNLOAD = True def helper(allowed_on_study, corrupt_access_id, corrupt_secret_key, researcher_admin, site_admin, batch_user, study_as_object_id, wrong_access_key, wrong_secret_key, is_test_study, corrupt_study_object_id): if not study_as_object_id and corrupt_study_object_id: # invalid test scenario, skip return