def test_invalid_cookie_cookietype(): # This is not actually a cookie only session, but we still test the cookie part. options = {"session.validate_key": "hoobermas", "session.type": "cookie"} app = TestApp(SessionMiddleware(simple_app, **options)) res = app.get("/") assert "current value is: 1" in res # Set an invalid cookie. app.set_cookie("cb_/zabbix/actionconf.php_parts", "HI") res = app.get("/") assert "current value is: 2" in res, res res = app.get("/") assert "current value is: 3" in res, res
def test_invalid_cookie_cookietype(): # This is not actually a cookie only session, but we still test the cookie part. options = {'session.validate_key':'hoobermas', 'session.type':'cookie'} app = TestApp(SessionMiddleware(simple_app, **options)) res = app.get('/') assert 'current value is: 1' in res # Set an invalid cookie. app.set_cookie('cb_/zabbix/actionconf.php_parts', 'HI') res = app.get('/') assert 'current value is: 2' in res, res res = app.get('/') assert 'current value is: 3' in res, res
class Saml2RequestTests(MongoTestCase): """Base TestCase for those tests usign saml2 that need a full environment setup """ def setUp(self, settings={}): super(Saml2RequestTests, self).setUp(celery, get_attribute_manager, userdb_use_old_format=True) self.settings = { 'saml2.settings_module': path.join(path.dirname(__file__), 'tests/data/saml2_settings.py'), 'saml2.login_redirect_url': '/', 'saml2.logout_redirect_url': '/', 'saml2.strip_saml_user_suffix': '@test', 'auth_tk_secret': '123456', 'testing': True, 'jinja2.directories': 'eduiddashboard:saml2/templates', 'jinja2.undefined': 'strict', 'jinja2.filters': """ route_url = pyramid_jinja2.filters:route_url_filter static_url = pyramid_jinja2.filters:static_url_filter """, 'session.key': 'sessid', 'session.secret': '123341234', 'session.cookie_domain': 'localhost', 'session.cookie_path': '/', 'session.cookie_max_age': '3600', 'session.cookie_httponly': True, 'session.cookie_secure': False, } self.settings.update(settings) if not self.settings.get('groups_callback', None): self.settings['groups_callback'] = dummy_groups_callback self.settings['mongo_uri'] = self.mongodb_uri('') self.redis_instance = RedisTemporaryInstance.get_instance() self.settings['REDIS_HOST'] = 'localhost' self.settings['REDIS_PORT'] = self.redis_instance._port self.settings['REDIS_DB'] = '0' self.redis_conn = redis.Redis(host='localhost', port=self.redis_instance._port, db=0) app = saml2_main({}, **self.settings) self.testapp = TestApp(app) self.config = testing.setUp() self.config.registry.settings = self.settings self.config.registry.registerUtility(self, IDebugLogger) self.userdb = app.registry.settings['userdb'] self.db = app.registry.settings['db'] def tearDown(self): super(Saml2RequestTests, self).tearDown() for k in self.redis_conn.keys(): self.redis_conn.delete(k) self.testapp.reset() def set_user_cookie(self, user_id): request = TestRequest.blank('', {}) request.registry = self.testapp.app.registry remember_headers = remember(request, user_id) cookie_value = remember_headers[0][1].split('"')[1] self.testapp.set_cookie('auth_tkt', cookie_value) return request def dummy_request(self): request = DummyRequest() request.context = DummyResource() request.userdb = self.userdb request.db = self.db request.registry.settings = self.settings return request def get_request_with_session(self): queryUtility = self.testapp.app.registry.queryUtility session_factory = queryUtility(ISessionFactory) request = self.dummy_request() session = session_factory(request) session.persist() self.testapp.set_cookie(self.settings['session.key'], session._session.token) self.pol = self.config.testing_securitypolicy( 'user', ('editors', ), permissive=False, remember_result=True) return request def get_fake_session_info(self, eppn=None): session_info = { 'authn_info': [ ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', []) ], 'name_id': None, 'not_on_or_after': 1371671386, 'came_from': u'/', 'ava': { 'cn': ['John'], 'objectclass': ['top', 'inetOrgPerson', 'person', 'eduPerson'], 'userpassword': ['1234'], 'edupersonaffiliation': ['student'], 'sn': ['Smith'], 'mail': ['*****@*****.**'], 'eduPersonPrincipalName': ['hubba-bubba@test'] }, 'issuer': 'https://idp.example.com/saml/saml2/idp/metadata.php' } if eppn is not None: session_info['ava']['eduPersonPrincipalName'] = eppn return session_info
class LoggedInRequestTests(MongoTestCase): """Base TestCase for those tests that need a logged in environment setup""" def setUp(self, settings={}, skip_on_fail=False, std_user='******'): self.settings = deepcopy(SETTINGS) self.settings.update(settings) super(LoggedInRequestTests, self).setUp(celery, get_attribute_manager, userdb_use_old_format=True) self.redis_instance = RedisTemporaryInstance.get_instance() self.settings['redis_host'] = 'localhost' self.settings['redis_port'] = self.redis_instance._port self.settings['redis_db'] = '0' self.settings['mongo_uri'] = self.mongodb_uri('') try: app = eduiddashboard_main({}, **self.settings) except pymongo.errors.ConnectionFailure: if skip_on_fail: raise unittest.SkipTest("requires accessible MongoDB server on {!r}".format( self.settings['mongo_uri'])) raise self.testapp = TestApp(app) self.config = testing.setUp() self.config.registry.settings = self.settings self.config.registry.registerUtility(self, IDebugLogger) self.userdb = app.registry.settings['userdb'] _userdoc = self.userdb.get_user_by_mail(std_user) self.assertIsNotNone(_userdoc, "Could not load the standard test user {!r} from the database {!s}".format( std_user, self.userdb)) self.user = OldUser(data=_userdoc) self.logged_in_user = None #self.db = get_db(self.settings) self.db = app.registry.settings['mongodb'].get_database('eduid_dashboard') # central userdb, raw mongodb self.userdb_new = UserDB(self.mongodb_uri(''), 'eduid_am') # central userdb in new format (User) self.dashboard_db = DashboardUserDB(self.mongodb_uri('eduid_dashboard')) # Clean up the dashboards private database collections logger.debug("Dropping profiles, verifications and reset_passwords from {!s}".format(self.db)) self.db.profiles.drop() self.db.verifications.drop() self.db.reset_passwords.drop() # Copy all the users from the eduid userdb into the dashboard applications userdb # since otherwise the out-of-sync check will trigger on every save to the dashboard # applications database because there is no document there with the right modified_ts for userdoc in self.userdb._get_all_docs(): logger.debug("Copying user {!r}\nfrom {!r}\nto {!r}:\n{!s}".format(userdoc.get('eduPersonPrincipalName'), self.userdb, self.db.profiles, pprint.pformat(userdoc))) self.db.profiles.insert(userdoc) self.initial_verifications = (getattr(self, 'initial_verifications', None) or INITIAL_VERIFICATIONS) for verification_data in self.initial_verifications: self.db.verifications.insert(verification_data) logger.debug("setUp finished\n\n" + ('-=-' * 30) + "\n\n") def tearDown(self): super(LoggedInRequestTests, self).tearDown() logger.debug("tearDown: Dropping profiles, verifications and reset_passwords from {!s}".format(self.db)) for userdoc in self.db.profiles.find({}): assert OldUser(userdoc) self.db.profiles.drop() self.db.verifications.drop() self.db.reset_passwords.drop() self.testapp.reset() def dummy_get_user(self, userid=''): return self.user def set_mocked_get_user(self): patcher = patch('eduid_userdb.dashboard.UserDBWrapper.get_user_by_eppn', self.dummy_get_user) patcher.start() def dummy_request(self, cookies={}): request = DummyRequest() request.context = DummyResource() request.userdb = self.userdb request.userdb_new = self.userdb_new request.db = self.db request.registry.settings = self.settings def propagate_user_changes(user): """ Make sure there is a request.context.propagate_user_changes in testing too. """ logger.debug('FREDRIK: Testing dummy_request.context propagate_user_changes') return self.request.amrelay.request_sync(user) request.context.propagate_user_changes = propagate_user_changes return request def set_logged(self, email='*****@*****.**', extra_session_data={}): request = self.set_user_cookie(email) user_obj = self.userdb.get_user_by_mail(email, raise_on_missing=True) if not user_obj: logging.error("User {!s} not found in database {!r}. Users:".format(email, self.userdb)) for this in self.userdb._get_all_userdocs(): this_user = OldUser(this) logging.debug(" User: {!s}".format(this_user)) # user only exists in eduid-userdb, so need to clear modified-ts to be able # to save it to eduid-dashboard.profiles user_obj.set_modified_ts(None) dummy = DummyRequest() dummy.session = { 'eduPersonAssurance': loa(3), 'eduPersonIdentityProofing': loa(3), } store_session_user(dummy, user_obj) # XXX ought to set self.user = user_obj self.logged_in_user = self.userdb_new.get_user_by_id(user_obj.get_id()) dummy.session.update(extra_session_data) request = self.add_to_session(dummy.session) return request def set_user_cookie(self, user_id): request = TestRequest.blank('', {}) request.registry = self.testapp.app.registry remember_headers = remember(request, user_id) cookie_value = remember_headers[0][1].split('"')[1] self.testapp.set_cookie('auth_tkt', cookie_value) return request def add_to_session(self, data): # Log warning since we're moving away from direct request.session access logger.warning('Add to session called with data: {!r}'.format(data)) queryUtility = self.testapp.app.registry.queryUtility session_factory = queryUtility(ISessionFactory) request = self.dummy_request() session = session_factory(request) for key, value in data.items(): session[key] = value session.persist() self.testapp.set_cookie(self.settings['session.key'], session._session.token) return request def check_values(self, fields, values, ignore_not_found=[]): for field in fields: if field.attrs['type'] == 'checkbox': # A webtest.app.Checkbox only has a value if it is checked (!) old_status = field.checked field.checked = True if field.value in values: logger.debug("Checked checkbox {!r} (value {!r})".format(field.id, field.value)) values.remove(field.value) else: # restore the checkbox whose value was not found in values field.checked = False values = [x for x in values if x not in ignore_not_found] self.assertEqual(values, [], "Failed checking one or more checkboxes: {!r}".format(values)) def values_are_checked(self, fields, values): checked = [f.value for f in fields if f.value is not None] self.assertEqual(values, checked) def sync_user_from_dashboard_to_userdb(self, user_id, old_format = True): """ When there is no eduid-dashboard-amp Attribute Manager plugin loaded to sync users from dashboard to userdb, this crude function can do it. :param user_id: User id :param old_format: Write in old format to userdb :type user_id: ObjectId :type old_format: bool :return: """ user = self.dashboard_db.get_user_by_id(user_id) logger.debug('Syncing user {!s} from dashboard to userdb'.format(user)) test_doc = {'_id': user_id} user_doc = user.to_dict(old_userdb_format=old_format) # Fixups to turn the DashboardUser into a User del user_doc['terminated'] self.userdb_new._coll.update(test_doc, user_doc, upsert=False)
class TestCookie(unittest.TestCase): """Tests API functions associated with VM actions. Note that all tests are in-process, we don't actually start a http server. """ def setUp(self): """Launch pserve using webtest with test settings""" self.appconf = get_app(test_ini) self.app = TestApp(self.appconf) # Punch in new administrator account with direct server call server.choose_engine("SQLite") # Sets global var "engine" - in the # case of SQLite this is a fresh RAM # DB each time. # Create new user. This will implicitly generate the tables. id1 = server.create_user(None, "testuser", "testuser", "testuser") server.touch_to_add_user_group("testuser", "users") server.touch_to_add_password(id1, "testpass") id2 = server.create_user(None, "administrator", "administrator", "administrator") server.touch_to_add_user_group("administrator", "administrators") server.touch_to_add_password(id2, "adminpass") """Confirm lack of any cookie without authentication.""" def test_no_cookie_without_auth(self): """ No cookie should be set when calling an endpoint that does not require authorization. """ self.app.authorization = None r = self.app.get("/", status=200) self.assertEqual(r.headers.get('Set-Cookie', 'empty'), 'empty') #Equivalently: self.assertEqual(self.app.cookies, {}) def test_no_username(self): """ The DB API should return a 401 unauthorised if I submit a request with no username / password provided. Similar to test_unauthenticated_api but with an extra check that no cookie is set. """ self.app.authorization = None r = self.app.get("/users/testuser", status=401) self.assertEqual(r.headers.get('Set-Cookie', 'empty'), 'empty') def test_invalid_username(self): """ The DB API should return a 401 unauthorised if I submit a bad username / password combination. And again no cookie """ self.app.authorization = ('Basic', ('invaliduser', 'invalidpassword')) r = self.app.get("/users/testuser", status=401) self.assertEqual(r.headers.get('Set-Cookie', 'empty'), 'empty') def test_valid_cookie(self): """Confirm cookie returned upon authentication. The DB API should return a cookie if I submit a correct username and password. The cookie should allow me to make a successful request using it alone. """ self.app.authorization = ('Basic', ('testuser', 'testpass')) r = self.app.get("/users/testuser", status=200) cookie = self.app.cookies['auth_tkt'] self.app.reset() # clear cookie cache self.app.authorization = None # remove auth credentials self.app.set_cookie("auth_tkt", cookie) # set cookie to old value r = self.app.get("/users/testuser", status=200) #Furthermore, we should still get the same cookie on the second call self.assertEqual(self.app.cookies['auth_tkt'], cookie) def test_broken_cookie(self): """ The DB API should refuse to service a request with a broken cookie. """ self.app.authorization = ('Basic', ('testuser', 'testpass')) r = self.app.get("/users/testuser", status=200) cookie = 'I am a fish' self.app.reset() # clear cookie cache self.app.authorization = None # remove auth credentials self.app.set_cookie("auth_tkt", cookie) # set cookie to bad value r = self.app.get("/users/testuser", status=401, expect_errors=False) def test_invalid_cookie(self): """ The DB API should refuse to service a request with an invalid cookie. """ self.app.authorization = ('Basic', ('testuser', 'testpass')) r = self.app.get("/users/testuser", status=200) cookie = '94514a32a7923939584470e8fc01f9b073bc3c8171542c8b7deb0' + \ 'dd459400945553f9ed9dGVzdHVzZXI%3D!userid_type:b64unicode' self.app.reset() # clear cookie cache self.app.authorization = None # remove auth credentials self.app.set_cookie("auth_tkt", cookie) # set cookie to bad value r = self.app.get("/users/testuser", status=401, expect_errors=False) def test_valid_authtkt(self): """Setting a cookie in the request is problematic for AJAX, so test that we can feed the token back in the auth_tkt header instead. """ self.app.authorization = ('Basic', ('testuser', 'testpass')) r = self.app.get("/users/testuser", status=200) cookie = self.app.cookies['auth_tkt'] self.app.reset() # clear cookie cache self.app.authorization = None # remove auth credentials r = self.app.get("/users/testuser", headers={'auth_tkt': cookie}, status=200) #Furthermore, we should still get the same cookie on the second call self.assertEqual(self.app.cookies['auth_tkt'], cookie) def test_broken_cookie(self): """ The DB API should refuse to service a request with a broken auth_tkt. And should return a 408 error (I think - we don't want a 401 as it causes the browser to prompt for a username/password which will then be remembered for basic auth) """ self.app.authorization = ('Basic', ('testuser', 'testpass')) r = self.app.get("/users/testuser", status=200) cookie = 'I am a fish' self.app.reset() # clear cookie cache self.app.authorization = None # remove auth credentials r = self.app.get("/users/testuser", headers={'auth_tkt': cookie}, status=408, expect_errors=False)
class LoggedInRequestTests(MongoTestCase): """Base TestCase for those tests that need a logged in environment setup""" def setUp(self, settings={}, skip_on_fail=False, std_user='******'): self.settings = deepcopy(SETTINGS) self.settings.update(settings) super(LoggedInRequestTests, self).setUp(celery, get_attribute_manager, userdb_use_old_format=True) self.redis_instance = RedisTemporaryInstance.get_instance() self.settings['redis_host'] = 'localhost' self.settings['redis_port'] = self.redis_instance._port self.settings['redis_db'] = '0' self.settings['mongo_uri'] = self.mongodb_uri('') try: app = eduiddashboard_main({}, **self.settings) except pymongo.errors.ConnectionFailure: if skip_on_fail: raise unittest.SkipTest( "requires accessible MongoDB server on {!r}".format( self.settings['mongo_uri'])) raise self.testapp = TestApp(app) self.config = testing.setUp() self.config.registry.settings = self.settings self.config.registry.registerUtility(self, IDebugLogger) #self.db = get_db(self.settings) self.db = app.registry.settings['mongodb'].get_database( 'eduid_dashboard') # central userdb, raw mongodb self.userdb_new = UserDB( self.mongodb_uri(''), 'eduid_am') # central userdb in new format (User) self.dashboard_db = DashboardUserDB( self.mongodb_uri('eduid_dashboard')) # Clean up the dashboards private database collections logger.debug( "Dropping profiles, verifications and reset_passwords from {!s}". format(self.db)) self.db.profiles.drop() self.db.verifications.drop() self.db.reset_passwords.drop() self.user = self.userdb_new.get_user_by_mail(std_user) self.assertIsNotNone( self.user, "Could not load the standard test user {!r} from the database {!s}" .format(std_user, self.userdb_new)) self.logged_in_user = None # Copy all the users from the eduid userdb into the dashboard applications userdb # since otherwise the out-of-sync check will trigger on every save to the dashboard # applications database because there is no document there with the right modified_ts for userdoc in self.userdb_new._get_all_docs(): logger.debug("COPYING USER INTO PROFILES:\n{!s}".format(userdoc)) self.db.profiles.insert(userdoc) self.initial_verifications = (getattr(self, 'initial_verifications', None) or INITIAL_VERIFICATIONS) for verification_data in self.initial_verifications: self.db.verifications.insert(verification_data) logger.debug("setUp finished\n\n" + ('-=-' * 30) + "\n\n") def tearDown(self): super(LoggedInRequestTests, self).tearDown() logger.debug( "tearDown: Dropping profiles, verifications and reset_passwords from {!s}" .format(self.db)) for userdoc in self.db.profiles.find({}): assert DashboardUser(data=userdoc) self.db.profiles.drop() self.db.verifications.drop() self.db.reset_passwords.drop() self.testapp.reset() def dummy_get_user(self, userid=''): return self.user def set_mocked_get_user(self): patcher = patch( 'eduid_userdb.dashboard.UserDBWrapper.get_user_by_eppn', self.dummy_get_user) patcher.start() def dummy_request(self, cookies={}): request = DummyRequest() request.context = DummyResource() request.context.request = request request.userdb_new = self.userdb_new request.db = self.db request.dashboard_userdb = self.dashboard_db request.registry.settings = self.settings def propagate_user_changes(user): """ Make sure there is a request.context.propagate_user_changes in testing too. """ logger.debug( 'FREDRIK: Testing dummy_request.context propagate_user_changes' ) return self.request.amrelay.request_sync(user) request.context.propagate_user_changes = propagate_user_changes return request def set_logged(self, email='*****@*****.**', extra_session_data={}): request = self.set_user_cookie(email) user_obj = self.userdb_new.get_user_by_mail(email, raise_on_missing=True) if not user_obj: logging.error( "User {!s} not found in database {!r}. Users:".format( email, self.userdb)) for this in self.userdb_new._get_all_userdocs(): this_user = DashboardUser(this) logging.debug(" User: {!s}".format(this_user)) # user only exists in eduid-userdb, so need to clear modified-ts to be able # to save it to eduid-dashboard.profiles user_obj.modified_ts = None dummy = DummyRequest() dummy.session = { 'eduPersonAssurance': loa(3), 'eduPersonIdentityProofing': loa(3), 'eduPersonPrincipalName': 'hubba-bubba', 'user_eppn': 'hubba-bubba', } store_session_user(dummy, user_obj) # XXX ought to set self.user = user_obj self.logged_in_user = self.userdb_new.get_user_by_id(user_obj.user_id) dummy.session.update(extra_session_data) request = self.add_to_session(dummy.session) return request def set_user_cookie(self, user_id): request = TestRequest.blank('', {}) request.registry = self.testapp.app.registry remember_headers = remember(request, user_id) cookie_value = remember_headers[0][1].split('"')[1] self.testapp.set_cookie('auth_tkt', cookie_value) return request def add_to_session(self, data): # Log warning since we're moving away from direct request.session access logger.warning('Add to session called with data: {!r}'.format(data)) queryUtility = self.testapp.app.registry.queryUtility session_factory = queryUtility(ISessionFactory) request = self.dummy_request() session = session_factory(request) for key, value in data.items(): session[key] = value session.persist() self.testapp.set_cookie(self.settings['session.key'], session._session.token) return request def check_values(self, fields, values, ignore_not_found=[]): for field in fields: if field.attrs['type'] == 'checkbox': # A webtest.app.Checkbox only has a value if it is checked (!) field.checked = True if field.value in values: logger.debug("Checked checkbox {!r} (value {!r})".format( field.id, field.value)) values.remove(field.value) else: # restore the checkbox whose value was not found in values field.checked = False values = [x for x in values if x not in ignore_not_found] self.assertEqual( values, [], "Failed checking one or more checkboxes: {!r}".format(values)) def values_are_checked(self, fields, values): checked = [f.value for f in fields if f.value is not None] self.assertEqual(values, checked) def sync_user_from_dashboard_to_userdb(self, user_id, old_format=False): """ When there is no eduid-dashboard-amp Attribute Manager plugin loaded to sync users from dashboard to userdb, this crude function can do it. :param user_id: User id :param old_format: Write in old format to userdb :type user_id: ObjectId :type old_format: bool :return: """ user = self.dashboard_db.get_user_by_id(user_id) logger.debug('Syncing user {!s} from dashboard to userdb'.format(user)) test_doc = {'_id': user_id} user_doc = user.to_dict(old_userdb_format=old_format) # Fixups to turn the DashboardUser into a User user_doc['terminated'] = True self.userdb_new._coll.update(test_doc, user_doc, upsert=False)