def process_login(items): """Hook to add token on POST to /sessions. Attempts to first login via LDAP (if enabled), then login via database. If the login is successful, the fields "username" and "password" are removed and the fields "user" and "token" are added, which will be stored in the db. If the login is unsuccessful, abort(401) Args: items (list): List of items as passed by EVE to post hooks. """ for item in items: username = item['username'] password = item['password'] # LDAP if (app.config.get('ldap_connector') and ldap.authenticate_user(username, password)): # Success, sync user and get token try: user = ldap.sync_one(username) app.logger.info("User '%s' was authenticated with LDAP" % username) except LDAPException: # Sync failed! Try to find user in db. user = _find_user(username) if user: app.logger.error( f"User '{username}' authenticated with LDAP and found " "in db, but LDAP sync failed.") else: status = (f"Login failed: user '{username}' authenticated " "with LDAP but not found in db, and LDAP sync " "failed.") app.logger.error(status) abort(401, description=debug_error_message(status)) _prepare_token(item, user['_id']) return # Database, try to find via nethz, mail or objectid user = _find_user(username) if user: app.logger.debug("User found in db.") if verify_password(user, item['password']): app.logger.debug("Login for user '%s' successful." % username) _prepare_token(item, user['_id']) return else: status = "Login failed: Password does not match!" app.logger.debug(status) abort(401, description=debug_error_message(status)) # Abort if everything else fails status = "Login with db failed: User not found!" app.logger.debug(status) abort(401, description=debug_error_message(status))
def process_login(items): """Hook to add token on POST to /sessions. Attempts to first login via LDAP (if enabled), then login via database. If the login is successful, the fields "username" and "password" are removed and the fields "user" and "token" are added, which will be stored in the db. If the login is unsuccessful, abort(401) Args: items (list): List of items as passed by EVE to post hooks. """ for item in items: username = item['username'] password = item['password'] # LDAP if (app.config.get('ldap_connector') and ldap.authenticate_user(username, password)): # Success, sync user and get token updated = ldap.sync_one(username) _prepare_token(item, updated['_id']) app.logger.info( "User '%s' was authenticated with LDAP" % username) return # Database, try to find via nethz, mail or objectid users = app.data.driver.db['users'] lookup = {'$or': [{'nethz': username}, {'email': username}]} try: objectid = ObjectId(username) lookup['$or'].append({'_id': objectid}) except InvalidId: pass # input can't be used as ObjectId user = users.find_one(lookup) if user: app.logger.debug("User found in db.") if verify_password(user, item['password']): app.logger.debug("Login for user '%s' successful." % username) _prepare_token(item, user['_id']) return else: status = "Login failed: Password does not match!" app.logger.debug(status) abort(401, description=debug_error_message(status)) # Abort if everything else fails status = "Login with db failed: User not found!" app.logger.debug(status) abort(401, description=debug_error_message(status))
def test_sync_one_no_results(self): """Test if sync one return None if there are no results.""" search_results = (i for i in []) # Mock generator search = 'amivapi.ldap._search' create = 'amivapi.ldap._create_or_update_user' with patch(search, return_value=search_results): with patch(create) as mock_create: query = "query" result = ldap.sync_one(query) self.assertEqual(result, None) mock_create.assert_not_called()
def process_login(items): """Hook to add token on POST to /sessions. Attempts to first login via LDAP (if enabled), then login via database. If the login is successful, the fields "username" and "password" are removed and the fields "user" and "token" are added, which will be stored in the db. If the login is unsuccessful, abort(401) Args: items (list): List of items as passed by EVE to post hooks. """ for item in items: username = item['username'] password = item['password'] # LDAP if (app.config.get('ldap_connector') and ldap.authenticate_user(username, password)): # Success, sync user and get token updated = ldap.sync_one(username) _prepare_token(item, updated['_id']) app.logger.info("User '%s' was authenticated with LDAP" % username) return # Database, try to find via nethz, mail or objectid users = app.data.driver.db['users'] lookup = {'$or': [{'nethz': username}, {'email': username}]} try: objectid = ObjectId(username) lookup['$or'].append({'_id': objectid}) except InvalidId: pass # input can't be used as ObjectId user = users.find_one(lookup) if user: app.logger.debug("User found in db.") if verify_password(user, item['password']): app.logger.debug("Login for user '%s' successful." % username) _prepare_token(item, user['_id']) return else: status = "Login failed: Password does not match!" app.logger.debug(status) abort(401, description=debug_error_message(status)) # Abort if everything else fails status = "Login with db failed: User not found!" app.logger.debug(status) abort(401, description=debug_error_message(status))
def test_sync_one_found(self): """Sync one queries ldap and creates user.""" search_results = (i for i in [1]) # Mock generator search = 'amivapi.ldap._search' create = 'amivapi.ldap._create_or_update_user' with patch(search, return_value=search_results) as mock_search: with patch(create, return_value=2) as mock_create: query = "Abcsdi123" result = ldap.sync_one(query) self.assertEqual(result, 2) mock_search.assert_called_with('(cn=%s)' % query) mock_create.assert_called_with(1)
def test_sync_one(self): """Assert synchronizing one user works.""" with self.app.test_request_context(): user = ldap.sync_one(LDAP_USER_NETHZ) data_only = {key: value for (key, value) in user.items() if not key.startswith('_')} # no meta fields # Double check with database db_user = self.db['users'].find_one({'nethz': LDAP_USER_NETHZ}) # Compare with database (ignore meta fields) for key in data_only: self.assertEqual(user[key], db_user[key]) # Display user data for manual verification message = 'Manual data check required:\n%s' % pformat(data_only) warnings.warn(UserWarning(message))
def test_sync_one(self): """Assert synchronizing one user works.""" with self.app.test_request_context(): user = ldap.sync_one(LDAP_USER_NETHZ) data_only = { key: value for (key, value) in user.items() if not key.startswith('_') } # no meta fields # Double check with database db_user = self.db['users'].find_one({'nethz': LDAP_USER_NETHZ}) # Compare with database (ignore meta fields) for key in data_only: self.assertEqual(user[key], db_user[key]) # Display user data for manual verification message = 'Manual data check required:\n%s' % pformat(data_only) warnings.warn(UserWarning(message))
def ldap_sync(config, sync_all, nethz): """Synchronize users with eth ldap. Examples: amivapi ldap_sync --all amivapi ldap_sync adietmue bconrad blumh """ app = create_app(config_file=config) if not app.config['ldap_connector']: echo("LDAP is not enabled, can't proceed!") else: with app.test_request_context(): if sync_all: res = ldap.sync_all() echo("Synchronized %i users." % len(res)) else: for user in nethz: if ldap.sync_one(user) is not None: echo("Successfully synchronized '%s'." % user) else: echo("Could not synchronize '%s'." % user)