def auth_meta_mw(resp): """ Callback for meta.wikimedia.org to send us authentication results. This is responsible for fetching existing users or creating new ones. If a new user is created, they get the default role of GUEST and an email or username to match their details from the OAuth provider. """ if resp is None: flash('You need to grant the app permissions in order to login.', 'error') return redirect(url_for('login')) session['access_token'] = ( resp['oauth_token'], resp['oauth_token_secret'] ) try: identify_token_encoded = meta_mw.post( app.config['META_MW_BASE_URL'] + app.config['META_MW_IDENTIFY_URI'], ).data identify_token = process_mw_jwt(identify_token_encoded) username = identify_token['username'] userid = identify_token['sub'] db_session = db.get_session() user = None try: user = db_session.query(UserStore).filter_by(meta_mw_id=userid).one() except NoResultFound: user = UserStore( username=username, meta_mw_id=userid, role=UserRole.GUEST, ) db_session.add(user) db_session.commit() except MultipleResultsFound: db_session.close() return 'Multiple users found with your id!!! Contact Administrator' user.login(db_session) try: if login_user(user): user.detach_from(db_session) redirect_to = session.get('next') or url_for('home_index') redirect_to = urllib2.unquote(redirect_to) return redirect(redirect_to) finally: db_session.close() except Exception, e: flash('Access to this application was revoked. Please re-login!') app.logger.exception(str(e)) return redirect(url_for('login'))
def auth_google(resp): """ Callback for Google to send us authentication results. This is responsible for fetching existing users or creating new ones. If a new user is created, they get the default role of GUEST and an email or username to match their details from the OAuth provider. """ if resp is None and request.args.get('error') == 'access_denied': flash('You need to grant the app permissions in order to login.', 'error') return redirect(url_for('login')) access_token = resp['access_token'] or request.args.get('code') if access_token: session['access_token'] = access_token, '' r = requests.get(app.config['GOOGLE_USERINFO_URI'], headers={ 'Authorization': 'OAuth ' + access_token }) if r.ok: userinfo = json.loads(r.text) email = userinfo['email'] id = userinfo['id'] db_session = db.get_session() user = None try: user = db_session.query(UserStore).filter_by(google_id=id).one() except NoResultFound: try: user = UserStore( email=email, google_id=id, role=UserRole.GUEST, ) db_session.add(user) db_session.commit() except Exception: db_session.rollback() raise except MultipleResultsFound: return 'Multiple users found with your id!!! Contact Administrator' user.login(db_session) if login_user(user): user.detach_from(db_session) redirect_to = session.get('next') or url_for('home_index') redirect_to = urllib2.unquote(redirect_to) return redirect(redirect_to) flash('Was not allowed to authenticate you with Google.', 'error') return redirect(url_for('login'))
def auth_meta_mw(): """ Callback for meta.wikimedia.org to send us authentication results. This is responsible for fetching existing users or creating new ones. If a new user is created, they get the default role of GUEST and an email or username to match their details from the OAuth provider. """ try: handshaker = make_handshaker_mw() raw_req_token = session['request_token'] request_token = RequestToken(key=raw_req_token[0], secret=raw_req_token[1]) access_token = handshaker.complete(request_token, request.query_string) session['access_token'] = access_token identity = handshaker.identify(access_token) username = identity['username'] userid = identity['sub'] db_session = db.get_session() user = None try: user = db_session.query(UserStore).filter_by(meta_mw_id=userid).one() except NoResultFound: try: user = UserStore( username=username, meta_mw_id=userid, role=UserRole.GUEST, ) db_session.add(user) db_session.commit() except Exception: db_session.rollback() raise except MultipleResultsFound: flash('Multiple users found with your id!!! Contact Administrator', 'error') return redirect(url_for('login')) user.login(db_session) if login_user(user): user.detach_from(db_session) del session['request_token'] except Exception: flash('You need to grant the app permissions in order to login.', 'error') app.logger.exception(traceback.format_exc()) return redirect(url_for('login')) redirect_to = session.get('next') or url_for('home_index') return redirect(urllib2.unquote(redirect_to))
def test_delete_cohort_owner_has_viewer(self): viewer_user = UserStore() self.session.add(viewer_user) self.session.commit() viewer_cohort_user = CohortUserStore(user_id=viewer_user.id, cohort_id=self.cohort.id, role=CohortUserRole.VIEWER) self.session.add(viewer_cohort_user) self.session.commit() response = self.app.post('/cohorts/delete/{0}'.format(self.cohort.id)) assert_equal(response.status_code, 200) assert_true(response.data.find('isRedirect') >= 0) assert_true(response.data.find('/cohorts/') >= 0) cohort_id = self.cohort.id self.session.commit() # Check that all relevant rows are deleted cwu = self.session.query(CohortWikiUserStore) \ .filter(CohortWikiUserStore.cohort_id == cohort_id) \ .first() assert_equal(cwu, None) cu = self.session.query(CohortUserStore) \ .filter(CohortUserStore.cohort_id == cohort_id) \ .first() assert_equal(cu, None) wu = self.session.query(WikiUserStore) \ .filter(WikiUserStore.validating_cohort == cohort_id) \ .first() assert_equal(wu, None) c = self.session.query(CohortStore).get(cohort_id) assert_equal(c, None)
def create_wiki_cohort(self, project=mediawiki_project): """ Creates a wiki cohort (spans a whole project) and an owner for the cohort """ # cohort data basic_wiki_cohort = CohortStore(name='{0}-wiki-cohort'.format(project), enabled=True, public=False, default_project=project, class_name='WikiCohort' ) self.session.add(basic_wiki_cohort) self.session.commit() self.basic_wiki_cohort = basic_wiki_cohort owner = UserStore(username='******', email='*****@*****.**') self.session.add(owner) self.session.commit() self.owner_user_id = owner.id cohort_user = CohortUserStore( user_id=self.owner_user_id, cohort_id=basic_wiki_cohort.id, role=CohortUserRole.OWNER ) self.session.add(cohort_user) self.session.commit() self.basic_wiki_cohort_owner = cohort_user
def setUp(self): QueueDatabaseTest.setUp(self) self.mwSession.add(MediawikiUser(user_name='Editor test-specific-0')) self.mwSession.add(MediawikiUser(user_name='Editor test-specific-1')) self.mwSession.commit() owner_user = UserStore() self.session.add(owner_user) self.session.commit() self.owner_user_id = owner_user.id
def load_user(user_id): """ Callback required by Flask-Login. Gets the User object from the database. """ db_session = db.get_session() try: user = UserStore.get(db_session, user_id) finally: db_session.close() return user
def auth_meta_mw(): """ Callback for meta.wikimedia.org to send us authentication results. This is responsible for fetching existing users or creating new ones. If a new user is created, they get the default role of GUEST and an email or username to match their details from the OAuth provider. """ try: handshaker = make_handshaker_mw() raw_req_token = session['request_token'] request_token = RequestToken(key=raw_req_token[0], secret=raw_req_token[1]) access_token = handshaker.complete(request_token, request.query_string) session['access_token'] = access_token identity = handshaker.identify(access_token) username = identity['username'] userid = identity['sub'] db_session = db.get_session() user = None try: user = db_session.query(UserStore).filter_by( meta_mw_id=userid).one() except NoResultFound: try: user = UserStore( username=username, meta_mw_id=userid, role=UserRole.GUEST, ) db_session.add(user) db_session.commit() except: db_session.rollback() raise except MultipleResultsFound: flash('Multiple users found with your id!!! Contact Administrator', 'error') return redirect(url_for('login')) user.login(db_session) if login_user(user): user.detach_from(db_session) del session['request_token'] except Exception: flash('You need to grant the app permissions in order to login.', 'error') app.logger.exception(traceback.format_exc()) return redirect(url_for('login')) redirect_to = session.get('next') or url_for('home_index') return redirect(urllib2.unquote(redirect_to))
def auth_google(resp): """ Callback for Google to send us authentication results. This is responsible for fetching existing users or creating new ones. If a new user is created, they get the default role of GUEST and an email or username to match their details from the OAuth provider. """ if resp is None and request.args.get('error') == 'access_denied': flash('You need to grant the app permissions in order to login.', 'error') return redirect(url_for('login')) access_token = resp['access_token'] or request.args.get('code') if access_token: session['access_token'] = access_token, '' r = requests.get(app.config['GOOGLE_USERINFO_URI'], headers={'Authorization': 'OAuth ' + access_token}) if r.ok: userinfo = json.loads(r.text) email = userinfo['email'] id = userinfo['id'] db_session = db.get_session() user = None try: user = db_session.query(UserStore).filter_by( google_id=id).one() except NoResultFound: try: user = UserStore( email=email, google_id=id, role=UserRole.GUEST, ) db_session.add(user) db_session.commit() except: db_session.rollback() raise except MultipleResultsFound: return 'Multiple users found with your id!!! Contact Administrator' user.login(db_session) if login_user(user): user.detach_from(db_session) redirect_to = session.get('next') or url_for('home_index') redirect_to = urllib2.unquote(redirect_to) return redirect(redirect_to) flash('Was not allowed to authenticate you with Google.', 'error') return redirect(url_for('login'))
def validate_cohort(self, filename): ''' Given a cohort file with usernames all users but one should validate. It will mingle the name of the 1st user. Parameters: filename : Name of a file that contains a cohort with user names test will search for file in tests/static/public folder ''' names = self.create_users_from_file(filename) # establish ownership for this cohort otherwise things do not work owner_user = UserStore(username='******', email='*****@*****.**') self.session.add(owner_user) self.session.commit() # creating here kind of like a cohortupload mock # flask forms do not lend themselves to easy mocking cohort_upload = MockCohort() cohort_upload.name = MockCohort() cohort_upload.name.data = 'testing-cohort' cohort_upload.description = MockCohort() cohort_upload.description.data = 'testing-cohort' cohort_upload.project = MockCohort() cohort_upload.project.data = mediawiki_project cohort_upload.validate_as_user_ids = MockCohort() cohort_upload.validate_as_user_ids.data = False cohort_upload.records = [] # mingle the name of the first user user not_valid_editor_name = 'Mr Not Valid' names[0] = not_valid_editor_name for name in names: cohort_upload.records.append({ 'raw_id_or_name': name, 'project': mediawiki_project, }) # TODO clear session situation? # all operations need to happen on the scope of the same session # but this session passed in is going to be closed vc = ValidateCohort.from_upload(cohort_upload, owner_user.id, self.session) cohort = self.session.query(CohortStore).first() self.session.commit() vc.validate_records(self.session, cohort) # now we need to assert that all users but the first one validate assert_equal( len( self.session.query(WikiUserStore).filter( WikiUserStore.validating_cohort == cohort.id).filter( WikiUserStore.valid).all()), len(names) - 1) # retrieve the user that should not be valid, make sure it is not indeed wiki_user = self.session.query(WikiUserStore)\ .filter(WikiUserStore.validating_cohort == cohort.id)\ .filter(WikiUserStore.raw_id_or_name == not_valid_editor_name).one() assert_false(wiki_user.valid)
def create_test_data( self, name='test-specific', editor_count=0, user_registrations=20130101000000, revisions_per_editor=0, revision_timestamps=None, revision_lengths=None, page_count=0, page_timestamps=None, page_namespaces=None, page_creator_index=None, owner_user_id=None, page_touched=20130102000000, user_email_token_expires=20200101000000, create_cohort=True, mw_session=None, ): """ Internal multi-purpose data creator. Creates a set of users and, if `name` is specified, wraps them in a cohort. """ if revision_timestamps is None: revision_timestamps = [] if revision_lengths is None: revision_lengths = [] if page_timestamps is None: page_timestamps = [] if page_namespaces is None: page_namespaces = [] if page_creator_index is None: page_creator_index = [] if type(revision_timestamps) is datetime: revision_timestamps = i(revision_timestamps) if type(revision_timestamps) is int: revision_timestamps = [ [revision_timestamps] * revisions_per_editor ] * editor_count if type(revision_lengths) is int: revision_lengths = [ [revision_lengths] * revisions_per_editor ] * editor_count if type(user_registrations) is int: user_registrations = [user_registrations] * editor_count project = mediawiki_project if create_cohort: cohort = CohortStore( name='{0}-cohort'.format(name), enabled=True, public=False, validated=True, ) self.session.add(cohort) self.session.commit() if not mw_session: mw_session = self.mwSession page = Page(page_namespace=0, page_title='{0}-page'.format(name), page_touched=page_touched) mw_session.add(page) mw_session.commit() mw_session.bind.engine.execute( MediawikiUser.__table__.insert(), [ { 'user_name': 'Editor {0}-{1}'.format(name, e), 'user_registration': user_registrations[e], 'user_email_token_expires': user_email_token_expires } for e in range(editor_count) ] ) mw_session.commit() self.add_centralauth_users(['Editor {0}-0'.format(name)], ['wiki', 'wiki2']) editors = mw_session.query(MediawikiUser)\ .filter(MediawikiUser.user_name.like('Editor {0}-%'.format(name)))\ .order_by(MediawikiUser.user_id)\ .all() # Create logging table records for each inserted user mw_session.bind.engine.execute( Logging.__table__.insert(), [ { 'log_user': editor.user_id, 'log_timestamp': editor.user_registration, 'log_title': editor.user_name, 'log_type': 'newusers', 'log_action': 'create', } for editor in editors ] ) mw_session.commit() if create_cohort: self.session.bind.engine.execute( WikiUserStore.__table__.insert(), [ { 'raw_id_or_name' : editor.user_name or editor.user_id, 'mediawiki_username' : editor.user_name, 'mediawiki_userid' : editor.user_id, 'project' : project, 'valid' : True, 'validating_cohort' : cohort.id, } for editor in editors ] ) self.session.commit() wiki_users = self.session.query(WikiUserStore)\ .filter( WikiUserStore.mediawiki_username.like('Editor {0}-%'.format(name)))\ .all() self.session.bind.engine.execute( CohortWikiUserStore.__table__.insert(), [ { 'cohort_id' : cohort.id, 'wiki_user_id' : wiki_user.id, } for wiki_user in wiki_users ] ) self.session.commit() mw_session.bind.engine.execute( Revision.__table__.insert(), [ { 'rev_page' : page.page_id, 'rev_user' : editors[e].user_id, 'rev_comment' : 'revision {0}, editor {1}'.format(r, e), 'rev_timestamp' : revision_timestamps[e][r] or UNICODE_NULL * 14, 'rev_len' : revision_lengths[e][r], # rev_parent_id will be set below, following chronology } for e, r in product(range(editor_count), range(revisions_per_editor)) ] ) mw_session.commit() revisions = mw_session.query(Revision)\ .filter(Revision.rev_page == page.page_id)\ .order_by(Revision.rev_id)\ .all() # add rev_parent_id chain in chronological order real_revisions = filter(lambda r: r.rev_timestamp, revisions) ordered_revisions = sorted(real_revisions, key=lambda r: r.rev_timestamp) for idx, revision in enumerate(ordered_revisions): if idx == 0: revision.rev_parent_id = 0 else: revision.rev_parent_id = ordered_revisions[idx - 1].rev_id mw_session.commit() if create_cohort: # establish ownership for this cohort if not owner_user_id: owner = UserStore(username='******', email='*****@*****.**') self.session.add(owner) self.session.commit() owner_user_id = owner.id self.session.add(CohortUserStore( user_id=owner_user_id, cohort_id=cohort.id, role=CohortUserRole.OWNER, )) self.session.commit() if page_count > 0: # create any additional pages if type(page_timestamps) is int: page_timestamps = [page_timestamps] * page_count if type(page_namespaces) is int: page_namespaces = [page_namespaces] * page_count if type(page_creator_index) is int: page_creator_index = [page_creator_index] * page_count mw_session.bind.engine.execute( Page.__table__.insert(), [ { 'page_namespace' : page_namespaces[p], 'page_title' : '{0}-additional-page-{1}'.format(name, p), 'page_touched' : page_touched } for p in range(page_count) ] ) mw_session.commit() pages = mw_session.query(Page)\ .filter(Page.page_title.like('{0}-additional-page-%'.format(name)))\ .order_by(Page.page_id)\ .all() mw_session.bind.engine.execute( Revision.__table__.insert(), [ { 'rev_page' : pages[p].page_id, 'rev_user' : editors[page_creator_index[p]].user_id, 'rev_comment' : 'page {0} created'.format(p), 'rev_timestamp' : page_timestamps[p], 'rev_len' : 10, 'rev_parent_id' : 0, } for p in range(page_count) ] ) mw_session.commit() if create_cohort: self.project = project # TODO this is a storage object, should be changed # for metrics tests into a logic object, not a storage object self.cohort = cohort self.page = page self.editors = editors self.editor_ids = [e.user_id for e in editors] self.revisions = revisions self.owner_user_id = owner_user_id
def load_user(user_id): """ Callback required by Flask-Login. Gets the User object from the database. """ db_session = db.get_session() return UserStore.get(db_session, user_id)