def get_roles(database: Database, db_user: str) -> List[Dict]: """ Get all user's roles with find privileges if user exists Args: database: MongoDB DB instance db_user: DB user name to get roles for Returns: List of roles found """ # usersInfo Command returns object in shape: # { # < some_other_keys > # 'users': [ # { # '_id': < auth_db >. < user >, # 'db': < auth_db >, # 'mechanisms': ['SCRAM-SHA-1', 'SCRAM-SHA-256'], # 'roles': [{'db': 'admin', 'role': 'readWriteAnyDatabase'}, # {'db': 'local', 'role': 'read'}], # 'user': < user >, # 'userId': < userId > # } # ] # } user_info = database.command({'usersInfo': db_user}) users = [u for u in user_info.get('users') if u.get('user') == db_user] if len(users) != 1: LOGGER.warning('Could not find any users for %s', db_user) return [] return get_roles_with_find_privs(database, users[0])
def getChanges(collName: str, db: database.Database, since: datetime.datetime) -> object: logging.info(f"Checking for changes since: {since}") pipeline = [ { "$changeStream": { "fullDocument": "updateLookup" } }, { "$match": { "operationType": { "$in": ["insert", "update", "replace"] } } }, { "$project": { "_id": 1, "fullDocument": 1, "ns": 1, "documentKey": 1 } } ] return db.command({ "aggregate": collName, "pipeline": pipeline, "startAtOperationTime": since })
def get_roles_with_find_privs(database: Database, user: Dict) -> List[Dict]: """ Finds and returns all the user's roles that have find privileges. User is dictionary in the form: { '_id': <auth_db>.<user>, 'db': <auth_db>, 'mechanisms': ['SCRAM-SHA-1', 'SCRAM-SHA-256'], 'roles': [{'db': 'admin', 'role': 'readWriteAnyDatabase'}, {'db': 'local', 'role': 'read'}], 'user': <user>, 'userId': <userId> } Args: database: MongoDB Database instance user: db user dictionary Returns: list of roles """ roles = [] for role in user.get('roles', []): if role.get('role') in ROLES_WITHOUT_FIND_PRIVILEGES: continue role_name = role['role'] # roles with find privileges if role_name in ROLES_WITH_FIND_PRIVILEGES and role.get('db'): roles.append(role) # for custom roles, get the "sub-roles" else: role_info_list = database.command( {'rolesInfo': { 'role': role_name, 'db': database.name }}) role_info = [ r for r in role_info_list.get('roles', []) if r['role'] == role_name ] if len(role_info) != 1: continue roles.extend([ sub_role for sub_role in role_info[0].get('roles', []) if sub_role.get('role') in ROLES_WITH_FIND_PRIVILEGES and sub_role.get('db') ]) return roles
def getMoreChanges(collName: str, db: database.Database, result: object) -> object: return db.command({ "getMore": result['cursor']['id'], "collection": collName })
class DatabaseConnection(object): """Establishes a connection to the mongodb.""" def __init__(self, database=None, host='localhost', port=27017): """ Can be initialized without parameters. :param database: Str name of database. :param host: Host. :param port: Port. """ self.timeout = 1 self.host = str(host) if not isinstance(port, int): raise ValueError( 'Entered port is "{}"! Must be integer type'.format(port)) self.port = port self.client = MongoClient(host=self.host, port=self.port, serverSelectionTimeoutMS=self.timeout) try: if database is not None: if database in self.client.database_names(): self.database = Database(self.client, database) if self.database.command("serverStatus")['ok'] == 1.0: print('connecting to: mongodb://{}:{}'.format( self.host, self.port)) print('database - "{}"'.format(self.database.name)) else: pass else: raise ValueError else: self.database = database except ServerSelectionTimeoutError as err: sys.exit('Error! {}'.format(err)) except ValueError: print('"{}" is not in database names! Please check the name of ' 'database!'.format(database)) def use_db(self, database=None): """ Switches between databases. :param database: Str name of database. """ try: if database in self.client.database_names(): self.database = Database(self.client, database) print('switched to db {}'.format(self.database.name)) else: raise ValueError except ServerSelectionTimeoutError as err: sys.exit('Error! {}'.format(err)) except ValueError: print('"{}" is not in database names! Please check the name of ' 'database!'.format(database)) def authenticate(self, user=None, password=None): """ Authenticates the user in the connected database. :param user: The name of the user. :param password: The password. """ if user is not None and password is not None: try: if user in [ user['user'] for user in ( self.database.command('usersInfo'))['users'] ]: try: if self.database.authenticate(user, password): self.auth = self.database.authenticate( user, password) print('1') else: raise OperationFailure except OperationFailure: print('Error: Authentication failed.') print('0') else: print('"{}" user is not in "{}" database users!'.format( user, self.database.name)) except AttributeError: print('At first you must connect to the database with use ' 'method!') else: print('Please check entered user and password!')