def __get_product(self, session, product): """ Retrieve the product connection object and create a Thrift Product object for the given product record in the database. """ server_product = self.__server.get_product(product.endpoint) if not server_product: LOG.info("Product '{0}' was found in the configuration " "database but no database connection was " "present. Mounting analysis run database...".format( product.endpoint)) self.__server.add_product(product) server_product = self.__server.get_product(product.endpoint) name = base64.b64encode(product.display_name.encode('utf-8')) descr = base64.b64encode(product.description.encode('utf-8')) \ if product.description else None args = {'config_db_session': session, 'productID': product.id} product_access = permissions.require_permission( permissions.PRODUCT_ACCESS, args, self.__auth_session) product_admin = permissions.require_permission( permissions.PRODUCT_ADMIN, args, self.__auth_session) return server_product, ttypes.Product( id=product.id, endpoint=product.endpoint, displayedName_b64=name, description_b64=descr, connected=server_product.db_status == shared.ttypes.DBStatus.OK, accessible=product_access, administrating=product_admin, databaseStatus=server_product.db_status)
def getCurrentProduct(self): """ Return information about the current product. The request MUST be routed as /product-name/ProductService! """ if not self.__product: msg = "Requested current product from ProductService but the " \ "request came through the main endpoint." LOG.error(msg) raise shared.ttypes.RequestFailed(shared.ttypes.ErrorCode.IOERROR, msg) try: session = self.__session() prod = session.query(Product).get(self.__product.id) server_product = self.__server.get_product(prod.endpoint) if not server_product: # TODO: Like above, better support this. LOG.error("Product '{0}' was found in the configuration " "database, but no database connection is " "present. Was the configuration database " "connected to multiple servers?" .format(prod.endpoint)) LOG.info("Please restart the server to make this " "product available.") raise shared.ttypes.RequestFailed( shared.ttypes.ErrorCode.DATABASE, "Product exists, but was not connected to this server.") name = base64.b64encode(prod.display_name.encode('utf-8')) descr = base64.b64encode(prod.description.encode('utf-8')) \ if prod.description else None args = {'config_db_session': session, 'productID': prod.id} product_access = permissions.require_permission( permissions.PRODUCT_ACCESS, args, self.__auth_session) product_admin = permissions.require_permission( permissions.PRODUCT_ADMIN, args, self.__auth_session) return ttypes.Product( id=prod.id, endpoint=prod.endpoint, displayedName_b64=name, description_b64=descr, connected=server_product.connected, accessible=product_access, administrating=product_admin) except sqlalchemy.exc.SQLAlchemyError as alchemy_ex: msg = str(alchemy_ex) LOG.error(msg) raise shared.ttypes.RequestFailed(shared.ttypes.ErrorCode.DATABASE, msg) finally: session.close()
def __get_product(self, session, product): """ Retrieve the product connection object and create a Thrift Product object for the given product record in the database. """ server_product = self.__server.get_product(product.endpoint) if not server_product: LOG.info("Product '{0}' was found in the configuration " "database but no database connection was " "present. Mounting analysis run database..." .format(product.endpoint)) self.__server.add_product(product) server_product = self.__server.get_product(product.endpoint) server_product.connect() num_of_runs = 0 latest_store_to_product = "" if server_product.db_status == shared.ttypes.DBStatus.OK: run_db_session = server_product.session_factory() num_of_runs = run_db_session.query(Run).count() if num_of_runs: last_updated_run = run_db_session.query(Run) \ .order_by(Run.date.desc()) \ .limit(1) \ .one_or_none() latest_store_to_product = last_updated_run.date name = base64.b64encode(product.display_name.encode('utf-8')) descr = base64.b64encode(product.description.encode('utf-8')) \ if product.description else None args = {'config_db_session': session, 'productID': product.id} product_access = permissions.require_permission( permissions.PRODUCT_ACCESS, args, self.__auth_session) product_admin = permissions.require_permission( permissions.PRODUCT_ADMIN, args, self.__auth_session) admin_perm_name = permissions.PRODUCT_ADMIN.name admins = session.query(ProductPermission). \ filter(and_(ProductPermission.permission == admin_perm_name, ProductPermission.product_id == product.id)) \ .all() return server_product, ttypes.Product( id=product.id, endpoint=product.endpoint, displayedName_b64=name, description_b64=descr, runCount=num_of_runs, latestStoreToProduct=str(latest_store_to_product), connected=server_product.db_status == shared.ttypes.DBStatus.OK, accessible=product_access, administrating=product_admin, databaseStatus=server_product.db_status, admins=[admin.name for admin in admins])
def __require_permission(self, required, args=None): """ Helper method to raise an UNAUTHORIZED exception if the user does not have any of the given permissions. """ try: if args is None: args = dict(self.__permission_args) session = self.__session() args['config_db_session'] = session if not any([ permissions.require_permission( perm, args, self.__auth_session) for perm in required ]): raise shared.ttypes.RequestFailed( shared.ttypes.ErrorCode.UNAUTHORIZED, "You are not authorized to execute this action.") return True except sqlalchemy.exc.SQLAlchemyError as alchemy_ex: msg = str(alchemy_ex) LOG.error(msg) raise shared.ttypes.RequestFailed(shared.ttypes.ErrorCode.DATABASE, msg) finally: if session: session.close()
def hasPermission(self, permission, extra_params): """ Returns whether or not the current logged-in user (or guest, if authentication is disabled) is granted the given permission. This method observes permission inheritance. """ with DBSession(self.__config_db) as session: perm, params = ThriftAuthHandler.__create_permission_args( permission, extra_params, session) return require_permission(perm, params, self.__auth_session)
def isAdministratorOfAnyProduct(self): try: session = self.__session() prods = session.query(Product).all() for prod in prods: args = {'config_db_session': session, 'productID': prod.id} if permissions.require_permission(permissions.PRODUCT_ADMIN, args, self.__auth_session): return True return False except sqlalchemy.exc.SQLAlchemyError as alchemy_ex: msg = str(alchemy_ex) LOG.error(msg) raise shared.ttypes.RequestFailed(shared.ttypes.ErrorCode.DATABASE, msg) finally: session.close()
def hasPermission(self, permission, extra_params): """ Returns whether or not the current logged-in user (or guest, if authentication is disabled) is granted the given permission. This method observes permission inheritance. """ try: session = self.__config_db() perm, params = ThriftAuthHandler.__create_permission_args( permission, extra_params, session) return require_permission(perm, params, self.__auth_session) except sqlalchemy.exc.SQLAlchemyError as alchemy_ex: msg = str(alchemy_ex) LOG.error(msg) raise shared.ttypes.RequestFailed(shared.ttypes.ErrorCode.DATABASE, msg) finally: session.close()
def getProducts(self, product_endpoint_filter, product_name_filter): """ Get the list of products configured on the server. """ result = [] try: session = self.__session() prods = session.query(Product) if product_endpoint_filter: prods = prods.filter(Product.endpoint.ilike('%{0}%'.format( util.escape_like(product_endpoint_filter)), escape='*')) if product_name_filter: prods = prods.filter(Product.display_name.ilike('%{0}%'.format( util.escape_like(product_name_filter)), escape='*')) prods = prods.all() for prod in prods: server_product = self.__server.get_product(prod.endpoint) if not server_product: # TODO: Better support this, if the configuration database # is mounted to multiple servers? LOG.error("Product '{0}' was found in the configuration " "database, but no database connection is " "present. Was the configuration database " "connected to multiple servers?" .format(prod.endpoint)) LOG.info("Please restart the server to make this " "product available.") continue # Clients are expected to use this method to query if # the product exists and usable. Usability sometimes requires # "updating" the "is connected" status of the database. if not server_product.connected: server_product.connect() name = base64.b64encode(prod.display_name.encode('utf-8')) descr = base64.b64encode(prod.description.encode('utf-8')) \ if prod.description else None args = {'config_db_session': session, 'productID': prod.id} product_access = permissions.require_permission( permissions.PRODUCT_ACCESS, args, self.__auth_session) product_admin = permissions.require_permission( permissions.PRODUCT_ADMIN, args, self.__auth_session) result.append(ttypes.Product( id=prod.id, endpoint=prod.endpoint, displayedName_b64=name, description_b64=descr, connected=server_product.connected, accessible=product_access, administrating=product_admin)) return result except sqlalchemy.exc.SQLAlchemyError as alchemy_ex: msg = str(alchemy_ex) LOG.error(msg) raise shared.ttypes.RequestFailed(shared.ttypes.ErrorCode.DATABASE, msg) finally: session.close()