class PermissionController(MetaResourceController): def __init__(self, connection=None, loglevel="INFO"): MetaResourceController.__init__(self, connection, loglevel) from porper.models.permission import Permission from porper.models.user_group import UserGroup self.permission = Permission(self.connection, loglevel) self.user_group = UserGroup(self.connection, loglevel) from porper.models.user import User from porper.models.group import Group self.user = User(self.connection, loglevel) self.group = Group(self.connection, loglevel) from porper.models.access_token import AccessToken self.access_token = AccessToken(self.connection, loglevel) # from porper.controllers.token_controller import TokenController # self.token_controller = TokenController(self.connection) # from porper.controllers.user_group_controller import UserGroupController # self.user_group_controller = UserGroupController(self.connection) from porper.models.permission import ALL self.PERMITTED_TO_ALL = ALL # def is_admin(self, user_id): # return self.user_group_controller.is_admin(user_id) # # def is_group_admin(self, user_id, group_id): # return self.user_group_controller.is_group_admin(user_id, group_id) # # def is_member(self, user_id, group_id): # return self.user_group_controller.is_member(user_id, group_id) # # def is_permitted(self, access_token, params): # """ # possible attributes in params # - None # - [user_id | group_id], action, resource, value # """ # current_user_id = self.token_controller.find_user_id(access_token) # if self.is_admin(current_user_id): return True # # #params['all'] = True # rows = self.find(access_token, params) # print("permitted : {}".format(rows)) # if len(rows) == 0: return False # return True def find_user_id(self, access_token): params = { 'access_token': access_token } return self.access_token.find(params)[0]['user_id'] def add_permissions_to_groups(self, resource_name, resource_id, permissions): #permissions: #[ # {"action": "r"}, # ... #] permission_params = { "resource": resource_name, "value": resource_id } for permission in permissions: permission_params["group_id"] = permission['id'] permission_params["action"] = permission['action'] if permission.get('condition'): permission_params['condition'] = permission['condition'] if permission['state'].lower() == "a": self.permission.create(permission_params) elif permission['state'].lower() == "u": self.permission.update(permission_params) elif permission['state'].lower() == "d": self.permission.delete(permission_params) def add_permissions_to_users(self, resource_name, resource_id, permissions): #permissions: #[ # {"action": "r"}, # ... #] permission_params = { "resource": resource_name, "value": resource_id } for permission in permissions: permission_params["user_id"] = permission['id'] permission_params["action"] = permission['action'] if permission.get('condition'): permission_params['condition'] = permission['condition'] if permission['state'].lower() == "a": self.permission.create(permission_params) elif permission['state'].lower() == "u": self.permission.update(permission_params) elif permission['state'].lower() == "d": self.permission.delete(permission_params) def add_permissions_to_customers(self, resource_name, resource_id, permissions): #permissions: #[ # {"action": "r"}, # ... #] permission_params = { "resource": resource_name, "value": resource_id } for permission in permissions: permission_params["customer_id"] = permission['id'] permission_params["action"] = permission['action'] if permission.get('condition'): permission_params['condition'] = permission['condition'] if permission['state'].lower() == "a": self.permission.create(permission_params) elif permission['state'].lower() == "u": self.permission.update(permission_params) elif permission['state'].lower() == "d": self.permission.delete(permission_params) def create_permissions_to_groups(self, resource_name, resource_id, to_group_ids): #permissions: #[ # {"action": "r"}, # ... #] # current_user_id = self.token_controller.find_user_id(access_token) # # # if the current is admin, allow it # if self.is_admin(current_user_id): # return self.add_permissions_to_group(resource_name, resource_id, permissions, to_group_id) if not self.is_admin: group_ids = [g['id'] for g in to_group_ids] customer_id = None user_id = None # if self.is_customer_admin: # customer_id = self.customer_id # else: # user_id = self.user_id # allow all users in the same customer customer_id = self.customer_id groups = self.group.find_by_ids(group_ids, customer_id= customer_id, user_id=user_id) if len(groups) != len(group_ids): self.logger.info("len(groups) = {} whereas len(to_group_ids) = {}".format(len(groups), len(group_ids))) raise Exception("not permitted") return self.add_permissions_to_groups(resource_name, resource_id, to_group_ids) """ # if the current user is NOT group admin of the given group, don't allow it if not self.is_group_admin(user_id, to_group_id): raise Exception("not permitted") # if 'create' is NOT in permissions to give # and the current user has 'create' permission in the speicified resource, allow it # if the specified group has a permission to 'create' on the specified resource, allow it if self.PERMISSION_TO_CREATE not in permissions: params = { 'action': 'create', 'resource': resource_name, 'value': resource_id } if self.is_permitted(access_token, params): return self.add_permissions_to_group(resource_name, resource_id, permissions, to_group_id) """ #raise Exception("not permitted") def create_permissions_to_users(self, resource_name, resource_id, to_user_ids): #permissions: #[ # {"action": "r"}, # ... #] if not self.is_admin: user_ids = [u['id'] for u in to_user_ids] customer_id = None user_id = None # if self.is_customer_admin: # customer_id = self.customer_id # else: # user_id = self.user_id # allow all users in the same customer customer_id = self.customer_id users = self.user.find_by_ids(user_ids, customer_id=customer_id, user_id=user_id) # get the unique users users = list(dict.fromkeys([u['id'] for u in users])) if len(users) != len(user_ids): self.logger.info("len(users) = {} whereas len(to_user_ids) = {}".format(len(users), len(user_ids))) raise Exception("not permitted") return self.add_permissions_to_users(resource_name, resource_id, to_user_ids) """ # if 'create' is NOT in permissions to give # and the current user has 'create' permission in the speicified resource, allow it # if the specified group has a permission to 'create' on the specified resource, allow it if self.PERMISSION_TO_CREATE not in permissions: params = { 'action': 'create', 'resource': resource_name, 'value': resource_id } if self.is_permitted(access_token, params): return self.add_permissions_to_group(resource_name, resource_id, permissions, to_group_id) """ #raise Exception("not permitted") def create_permissions_to_customer(self, resource_name, resource_id, to_customer_ids): #permissions: #[ # {"action": "r"}, # ... #] if not self.is_admin: # check if this user is in the same customer with the customer to give access for customer_id in [c['id'] for c in to_customer_ids]: if self.customer_id != customer_id: raise Exception("not permitted") return self.add_permissions_to_customers(resource_name, resource_id, to_customer_ids) def create(self, access_token, params): # { # "owner_id": "35925", "res_name": "meta", "res_id": "d392909c-d15f-43ff-98b4-9fd7e3ca80e9", # "to_user_ids": [{"id": "*****@*****.**", "action": "w", "state": "A"}, # {"id": "*****@*****.**", "action": "r", "state, "state": "A"}], # "to_group_ids": [{"id": "group_id1", "action": "w", "state": "A"}, # {"id": "group_id2", "action": "r", "state": "A"}], # "to_customer_ids": [{"id": "customer_id1", "action": "w", "state": "A"} # {"id": "customer_id1", "action": "r", "state": "A"}] # } owner_id = params.get('owner_id') self.find_user_level(access_token) if self.user_id != owner_id: raise Exception("not permitted") if params.get('to_group_ids'): self.create_permissions_to_groups(params['res_name'], params['res_id'], params['to_group_ids']) if params.get('to_user_ids'): self.create_permissions_to_users(params['res_name'], params['res_id'], params['to_user_ids']) if params.get('to_customer_ids'): self.create_permissions_to_customer(params['res_name'], params['res_id'], params['to_customer_ids']) return True def update(self, access_token, params): user_id = self.find_user_id(access_token) raise Exception("not supported") # This is to remove all permissions of given resource def delete(self, access_token, params): user_id = self.find_user_id(access_token) owner_id = params.get('owner_id') self.find_user_level(access_token) if self.user_id != owner_id: raise Exception("not permitted") if 'res_name' not in params or 'res_id' not in params: raise Exception("resource name and id are not provided") params['value'] = params['res_id'] del params['res_id'] return self.permission.delete(params) # def _filter_conditions(self, user_id, rows): # # filtered = [ row for row in rows if not row.get('condition') ] # if len(filtered) == len(filtered): # # there is no row with a condition # return rows # # permissions = [ row for row in rows if row.get('condition') ] # for permission in permissions: # condition = json.loads(permission['condition']) # # check when the condition is 'is_admin' and it is satisified, add it to the return list if so # if 'is_admin' in condition: # if not user_id \ # or not condition['is_admin'] \ # or ( permission.get('group_id') and self.is_group_admin(user_id, permission['group_id']) ): # filtered.append(permission) # # return filtered def find(self, access_token, params): """ possible attributes in params - None - [user_id | group_id], action, resource, [value] """ search_params = {} if params: if 'res_name' in params: search_params['res_name'] = params['res_name'] if 'action' in params: search_params['action'] = params['action'] if 'res_id' in params: search_params['value'] = params['res_id'] self.find_user_level(access_token) owner_id = params.get('owner_id') search_cid = None search_gids = None search_uids = None if not self.is_admin and ('res_id' not in params or owner_id != self.user_id): customer_id = None user_id = None # Allow customer admin to see only its and shared graphs like normal users # if self.is_customer_admin: # customer_id = self.customer_id # else: # user_id = self.user_id user_id = self.user_id groups = self.group.find({}, customer_id= customer_id, user_id=user_id) # do not allow users in the same groups with this user # users = self.user.find({}, customer_id= customer_id, user_id=user_id) search_cid = self.customer_id search_gids = [g['id'] for g in groups] # search_uids = [u['id'] for u in users] search_uids = [user_id] ret = self.permission.find_resource_permissions(search_params, search_cid, search_gids, search_uids) if params.get("value_only"): ret = self.get_values(ret) return ret def get_values(self, permissions): ret = [] for permission in permissions: if permission['value'] not in ret: ret.append(permission['value']) return ret
import sys sys.path.append("..") import os import boto3 region = os.environ.get('AWS_DEFAULT_REGION') dynamodb = boto3.resource('dynamodb', region_name=region) ######################################################################################################### # Preparation # Find the access_token of an admin ######################################################################################################### from porper.models.group import Group group = Group(dynamodb) admin_group = group.find({'name': 'admin'})[0] from util import find_token admin_access_token = find_token(admin_group['id']) # find a group from porper.controllers.group_controller import GroupController group_controller = GroupController(dynamodb) groups = group_controller.find(admin_access_token, {}) ### Invite a user from porper.controllers.invited_user_controller import InvitedUserController invited_user_controller = InvitedUserController(dynamodb) email_address = "*****@*****.**" item = { 'email': email_address,
class GroupController(MetaResourceController): def __init__(self, connection=None, loglevel="INFO"): #self.connection = connection MetaResourceController.__init__(self, connection, loglevel) from porper.models.group import Group self.group = Group(self.connection, loglevel) from porper.models.user import User self.user = User(self.connection, loglevel) # from porper.controllers.user_group_controller import UserGroupController # self.user_group_controller = UserGroupController(self.connection) self.permission_name = 'group' # only the admin can create a group def create(self, access_token, params): """ possible attributes in params - [id], name """ self.logger.info(f"params={params}") self.logger.info(f"access_token={access_token}") # self.logger.info(f"paths={paths}") self.find_user_level(access_token) if not self.is_permitted(self.permission_name, self.permission_write): raise Exception("not permitted") if "customer_id" not in params or not self.is_member( customer_id=params['customer_id']): raise Exception("not permitted") return self.group.create(params) def update(self, access_token, params): """ possible attributes in params - id, name """ self.logger.info(f'group_controller_update-params={params}') self.logger.info( f'group_controller_update-access_token={access_token}') self.find_user_level(access_token) if not self.is_permitted(self.permission_name, self.permission_write): raise Exception("not permitted") item = self.group.find_by_id(params['id']) if not item or not self.is_member(customer_id=item['customer_id']): raise Exception("not permitted") if params.get('customer_id'): raise Exception('You cannot update the group customer') if 'name' in params: ret = self.group.find({'name': params['name']}) if ret and ret[0]['id'] != params['id']: raise Exception("the group name already exists") return self.group.update(params) def delete(self, access_token, params): """ possible attributes in params - id """ self.find_user_level(access_token) if not self.is_permitted(self.permission_name, self.permission_write): raise Exception("not permitted") item = self.group.find_by_id(params['id']) if not item or not self.is_member(customer_id=item['customer_id']): raise Exception("not permitted") # cannot remove it when it has users users = self.user.find({'group_id': params['id']}) if len(users) > 0: raise Exception( "You must remove all users before removing this group") return self.group.delete(params['id']) def find(self, access_token, params): """ possible attributes in params - user_id: find all groups where this given user belongs - id: find a specific group - ids: find specific groups - None: No condition - name """ self.find_user_level(access_token) if 'closed' in params: if not self.is_permitted(self.permission_name, self.permission_read): raise Exception("not permitted") customer_id = None user_id = None if 'closed' in params: # allow users/groups of the groups only this user belongs if self.is_customer_admin: customer_id = self.customer_id elif not self.is_admin: user_id = self.user_id del params['closed'] else: # allow all users/groups of the customer this user belongs if not self.is_admin: customer_id = self.customer_id if 'ids' in params: groups = self.group.find_by_ids(params['ids'], customer_id=customer_id, user_id=user_id) return groups else: groups = self.group.find(params, customer_id=customer_id, user_id=user_id) if groups and 'id' in params: return groups[0] return groups
import sys sys.path.append("..") import os import boto3 region = os.environ.get('AWS_DEFAULT_REGION') dynamodb = boto3.resource('dynamodb', region_name=region) ######################################################################################################### # Preparation # Find the access_token of an admin ######################################################################################################### from porper.models.group import Group group = Group(dynamodb) admin_group = group.find({'name': 'admin'})[0] public_group = group.find({'name': 'public'})[0] from util import find_token admin_access_token = find_token(admin_group['id']) public_access_token = find_token(public_group['id']) from porper.controllers.token_controller import TokenController token_controller = TokenController(dynamodb) # find all access_tokens ret = token_controller.find(admin_access_token, {}) # find this user's access_token ret = token_controller.find(public_access_token, {})
class MetaResourceController: def __init__(self, connection=None, loglevel="INFO"): self.logger = logging.getLogger() # loglevel = "INFO" logging.basicConfig(level=logging.ERROR) aws_lambda_logging.setup(level=loglevel) if not connection: host = os.environ.get('MYSQL_HOST') username = os.environ.get('MYSQL_USER') password = os.environ.get('MYSQL_PASSWORD') database = os.environ.get('MYSQL_DATABASE') self.connection = pymysql.connect(host, user=username, passwd=password, db=database, cursorclass=pymysql.cursors.DictCursor) self.logger.debug("@@@@@@@@new connection created") else: self.connection = connection from porper.models.customer import Customer self.customer = Customer(self.connection, loglevel) from porper.models.group import Group self.group = Group(self.connection, loglevel) from porper.models.access_token import AccessToken self.access_token = AccessToken(self.connection, loglevel) from porper.models.permission import Permission self.permission = Permission(self.connection, loglevel) # from porper.models.user_group import UserGroup # self.user_group = UserGroup(self.connection) # from porper.controllers.token_controller import TokenController # self.token_controller = TokenController(self.connection) self.permissions = None self.user_id = None self.customer_id = None self.permission_name = None self.is_admin = False self.is_customer_admin = False self.permission_read = PERMISSION_READ self.permission_write = PERMISSION_WRITE # self.USER_LEVEL_ADMIN = 'admin' # self.USER_LEVEL_CUSTOMER_ADMIN = 'customer_admin' # # self.USER_LEVEL_GROUP_ADMIN = 'group_admin' # self.USER_LEVEL_USER = '******' @property def model_name(self): return self.model.__class__.__name__ # def find_permissions(self, user_id): # sql = """ # select p.res_name name, p.action action, p.value value # from User u # inner join Group_User gu on gu.user_id = u.id # inner join `Group` g on g.id = gu.group_id # inner join Role r on g.role_id = r.id # inner join Role_Function rf on rf.role_id = r.id # inner join Function f on rf.function_id = f.id # inner join Function_Permission fp on fp.function_id = f.id # inner join Permission p on fp.permission_id = p.id # where p.group_id is null and p.user_id is null and u.id = '{}' # """ # return self.find_by_sql(sql.format(user_id)) # def find_permissions(self, user_id, name, action, value=None): # # sql = """ # select f.id function_id, f.name function_name, p.id permission_id, # p.res_name resource_name, p.action action, p.value resource_id # from User u # inner join Group_User gu on gu.user_id = u.id # inner join `Group` g on g.id = gu.group_id # inner join Role r on g.role_id = r.id # inner join Role_Function rf on rf.role_id = r.id # inner join Function f on rf.function_id = f.id # inner join Function_Permission fp on fp.function_id = f.id # inner join Permission p on fp.permission_id = p.id # where u.id = '{}' and p.res_name = '{}' and p.action = '{}' # """ # if value: # sql += " and p.value = '{}'".format(value) # # return self.find_by_sql(sql.format(user_id)) # # if rows: # # return (True, rows[0]['resource_id']) # # return (False, None) def find_current_user(self, access_token): return self.access_token.find_user(access_token) # def is_admin(self, user_id): # rows = self.find_permissions(user_id, ADMIN_PERMISSION, PERMISSION_WRITE) # if rows: # return True # return False # # # def is_customer_admin(self, user_id, customer_id=None, group_id=None): # # if customer_id is None and group_id: # # find the customer_id of this given group # row = self.group.find_by_id(group_id) # if row: # customer_id = row['customer_id'] # # rows = self.find_permissions(user_id, CUSTOMER_ADMIN_PERMISSION, PERMISSION_WRITE, customer_id) # if rows: # return rows[0]['customer_id'] # return None # # # # def is_group_admin(self, user_id, group_id): # # rows = self.user_group.find({'user_id': user_id, 'group_id': group_id}) # # if len(rows) > 0 and rows[0]['is_admin']: return True # # else: return False def find_user_level(self, access_token): self.user_id = self.find_current_user(access_token)['id'] self.permissions = self.permission.find({'user_id': self.user_id}) self.customer_id = self.customer.find({'user_id': self.user_id})[0]['id'] if [p for p in self.permissions if p['name'] == ADMIN_PERMISSION]: self.is_admin = True elif [p for p in self.permissions if p['name'] == CUSTOMER_ADMIN_PERMISSION]: self.is_customer_admin = True # def is_admin(self): # return self.level == USER_LEVEL_ADMIN # # # def is_customer_admin(self): # return self.level == USER_LEVEL_CUSTOMER_ADMIN # # # def is_user(self): # return self.level == USER_LEVEL_USER # def find_user_val(self, access_token): # #This is used only for the invite block # user_id = self.token_controller.find_user_id(access_token) # return {"id": user_id} def is_permitted(self, name, action, value=None): # if self.is_admin(): # return True # if self.is_customer_admin(): # if name in ADMIN_PERMISSIONS and action == PERMISSION_WRITE: # return False # else: # return True permitted = [p['value'] for p in self.permissions if p['name'] == name and p['action'] == action] if not permitted: return False if value and value not in permitted: return False return True def is_member(self, customer_id=None, group_id=None): if self.is_admin: return True if customer_id: return self.customer_id == customer_id else: if self.is_customer_admin: if self.group.find({'group_id': group_id}, self.customer_id): return True else: if self.group.find({'group_id': group_id}, self.user_id): return True return False def commit(self): self.connection.commit() def rollback(self): self.connection.rollback()
import os import boto3 region = os.environ.get('AWS_DEFAULT_REGION') dynamodb = boto3.resource('dynamodb', region_name=region) ######################################################################################################### # Preparation ######################################################################################################### ###### Find non-admin groups # find all groups from porper.models.group import Group group = Group(dynamodb) groups = group.find({}) group_ids = [g['id'] for g in groups] role_ids = list(set([g['role_id'] for g in groups if 'role_id' in g])) # find all roles from porper.models.role import Role role = Role(dynamodb) roles = role.find_by_ids(role_ids) # find non admin roles ADMIN_FUNCTION_IDS = [ "883b3842-35bb-4070-917f-a501e87bd695", "85af95c8-a6f5-4e14-9cf9-11bbced53255" ] for r in roles: for f in r['functions']:
class AuthController(): def __init__(self, connection=None, loglevel="INFO"): self.logger = logging.getLogger() # loglevel = "INFO" logging.basicConfig(level=logging.ERROR) aws_lambda_logging.setup(level=loglevel) if not connection: host = os.environ.get('MYSQL_HOST') username = os.environ.get('MYSQL_USER') password = os.environ.get('MYSQL_PASSWORD') database = os.environ.get('MYSQL_DATABASE') self.connection = pymysql.connect( host, user=username, passwd=password, db=database, cursorclass=pymysql.cursors.DictCursor) self.logger.debug("@@@@@@@@new connection created") else: self.connection = connection # from porper.controllers.user_controller import UserController # self.user_controller = UserController(self.connection) # from porper.controllers.invited_user_controller import InvitedUserController # self.invited_user_controller = InvitedUserController(self.connection) # from porper.controllers.token_controller import TokenController # self.token_controller = TokenController(self.connection) # from porper.models.access_token import AccessToken # self.access_token = AccessToken(self.connection) from porper.models.user import User self.user = User(self.connection, loglevel) from porper.models.user_group import UserGroup self.user_group = UserGroup(self.connection, loglevel) from porper.models.group import Group self.group = Group(self.connection, loglevel) from porper.models.invited_user import InvitedUser self.invited_user = InvitedUser(self.connection, loglevel) from porper.models.access_token import AccessToken self.access_token = AccessToken(self.connection, loglevel) def authenticate(self, params): user_id = params['user_id'] email = params.get('email') family_name = params.get('family_name') given_name = params.get('given_name') name = params.get('name') customer_id = params.get('customer_id') auth_type = params['auth_type'] access_token = params['access_token'] refresh_token = params['refresh_token'] # print("Before invite") # items = self.invited_user.find({'email': params['email'], 'auth_type': params['auth_type']}) # if items and auth_type == "sso": # customer_id=items[0]['customer_id'] # print(customer_id) #if not invited_user: # print("Invited user not found") #else: # print("Printing invited user") # print(invited_user) user = self.user.find_by_id(user_id) if not user: # create this user params = {'id': user_id, 'auth_type': auth_type} if name: params['name'] = name if family_name: params['family_name'] = family_name if given_name: params['given_name'] = given_name if customer_id: params['customer_id'] = customer_id if email: params['email'] = email.lower() # # find admin user's access_token to replace this user's access_token to create a user # users = self.user.find({}) # if not users: # # this is the first user, so no need to set access_token # admin_access_token = None # else: # admin_access_token = self.access_token.find_admin_token() # user_id = self.user_controller.create(admin_access_token, params) user_id = self.add_user(params) # now save the tokens # return self.token_controller.save(access_token, refresh_token, user_id) params = { "access_token": access_token, "refresh_token": refresh_token, "user_id": user_id } self.access_token.create(params) user_info = self.user.find_by_id(user_id) user_info['user_id'] = user_info['id'] user_info['access_token'] = access_token user_info['groups'] = self.group.find({"user_id": user_id}) user_info['customer_id'] = user_info['groups'][0]['customer_id'] return user_info def add_user(self, params): # if this is the first user, save it as an admin users = self.user.find({}) if len(users) == 0: # set this user to the admin self.user.create(params) admin_groups = self.group.find_admin_groups() if not admin_groups: raise Exception("No admin group found") self.user_group.create({ 'user_id': params['id'], 'group_id': admin_groups[0]['id'] }) return params['id'] # # add the given user to the specified group # if params.get("group_id"): # return self.user_group.create( # { # "user_id": params['id'], # "group_id": params["group_id"] # } # ) # # # find if the given user already exists # rows = self.user.find({"email": params['email'], "auth_type": params['auth_type']}) # if len(rows) > 0: # print('already exists') # return rows[0]['id'] # find if the given user is already invited invited_users = self.invited_user.find({ 'email': params['email'], 'auth_type': params['auth_type'] }) if len(invited_users) == 0: raise Exception("Please invite this user first") # add user_group_rel first to check the permission # if the current user is not admin and group admin, it will fail # check if the current user is the admin of the invited user's group #if current_user['level'] != self.USER_LEVEL_ADMIN and not self.is_group_admin(current_user['user_id'], invited_users[0]['group_id']): # raise Exception("Not permitted") # create a user and add it to the specified group self.user.create({ 'id': params['id'], 'email': params['email'], 'auth_type': params['auth_type'], 'name': params['name'], 'family_name': params['family_name'], 'given_name': params['given_name'], #'customer_id': params['customer_id'] }) self.user_group.create({ 'user_id': params['id'], 'group_id': invited_users[0]['group_id'] }) self.invited_user.update_state(params['email'], params['auth_type'], self.invited_user.REGISTERED) self.commit() return params['id'] # def find_groups(self, user_id): # from porper.models.user_group import UserGroup # user_group = UserGroup(self.connection) # user_groups = user_group.find({'user_id': user_id}) # return user_groups def commit(self): self.connection.commit() def rollback(self): self.connection.rollback()