Ejemplo n.º 1
0
def check_nonce():
    """
    This function is an agaveflask authentication callback used to process the existence of a query parameter,
    x-nonce, an alternative authentication mechanism to JWT.
    
    When an x-nonce query parameter is provided, the request context is updated with the identity of the user owning
    the actor to which the nonce belongs. Note that the roles of said user will not be calculated so, in particular, 
    any privileged action cannot be taken via a nonce. 
    """
    logger.debug("top of check_nonce")
    try:
        nonce_id = request.args['x-nonce']
    except KeyError:
        raise PermissionsException("No JWT or nonce provided.")
    logger.debug("checking nonce with id: {}".format(nonce_id))
    # the nonce encodes the tenant in its id:
    g.tenant = Nonce.get_tenant_from_nonce_id(nonce_id)
    g.api_server = get_api_server(g.tenant)
    logger.debug("tenant associated with nonce: {}".format(g.tenant))
    # get the actor_id base on the request path
    actor_id = get_db_id()
    logger.debug("db_id: {}".format(actor_id))
    level = required_level(request)
    Nonce.check_and_redeem_nonce(actor_id, nonce_id, level)
    # if we were able to redeem the nonce, update auth context with the actor owner data:
    logger.debug("nonce valid and redeemed.")
    nonce = Nonce.get_nonce(actor_id, nonce_id)
    g.user = nonce.owner
    # update roles data with that stored on the nonce:
    g.roles = nonce.roles
    # now, manually call our authorization function:
    authorization()
Ejemplo n.º 2
0
 def get_agave(self, tenant, actor_owner):
     """
     Generate an agavepy client representing a specific user owning an actor.
     The `actor_owner` should be the username associated with the owner of the actor.
     """
     # these are the credentials of the abaco service account. this account should have the abaco and
     # impersonator roles.
     username = self.credentials[tenant.upper()]['username']
     password = self.credentials[tenant.upper()]['password']
     if username == '' or password == '':
         msg = 'Client service credentials not defined for tenant {}'.format(
             tenant)
         logger.error(msg)
         raise ClientException(msg)
     api_server = get_api_server(tenant)
     verify = get_tenant_verify(tenant)
     # generate an Agave client set up for admin_password representing the actor owner:
     logger.info("Attempting to generate an agave client.")
     try:
         return api_server, Agave(api_server=api_server,
                                  username=username,
                                  password=password,
                                  token_username=actor_owner,
                                  verify=verify)
     except Exception as e:
         msg = "Got exception trying to instantiate Agave object; exception: {}".format(
             e)
         logger.error(msg)
         raise ClientException(msg)
Ejemplo n.º 3
0
def process_event_msg(msg):
    """
    Process an event msg on an event queue
    :param msg: 
    :return: 
    """
    logger.debug("top of process_event_msg; raw msg: {}".format(msg))
    try:
        tenant_id = msg['tenant_id']
    except Exception as e:
        logger.error(
            "Missing tenant_id in event msg; exception: {}; msg: {}".format(
                e, msg))
        raise e
    link = msg.get('_abaco_link')
    webhook = msg.get('_abaco_webhook')
    logger.debug("processing event data; "
                 "tenant_id: {}; link: {}; webhook: {}".format(
                     tenant_id, link, webhook))
    # additional metadata about the execution
    d = {}
    d['_abaco_Content_Type'] = 'application/json'
    d['_abaco_username'] = '******'
    d['_abaco_api_server'] = get_api_server(tenant_id)
    if link:
        process_link(link, msg, d)
    if webhook:
        process_webhook(webhook, msg, d)
    if not link and not webhook:
        logger.error("No link or webhook. Ignoring event. msg: {}".format(msg))
Ejemplo n.º 4
0
def get_service_client(tenant):
    """Returns the service client for a specific tenant."""
    service_token = os.environ.get('_abaco_{}_service_token'.format(tenant))
    if not service_token:
        raise ClientException(
            "No service token configured for tenant: {}".format(tenant))
    api_server = get_api_server(tenant)
    verify = get_tenant_verify(tenant)
    # generate an Agave client with the service token
    logger.info("Attempting to generate an agave client.")
    return Agave(api_server=api_server, token=service_token, verify=verify)
Ejemplo n.º 5
0
def clean_up_apim_clients(tenant):
    """Check the list of clients registered in APIM and remove any that are associated with retired workers."""
    username = os.environ.get('_abaco_{}_username'.format(tenant), '')
    password = os.environ.get('_abaco_{}_password'.format(tenant), '')
    if not username:
        msg = "Health process did not get a username for tenant {}; " \
              "returning from clean_up_apim_clients".format(tenant)
        if tenant in ['SD2E', 'TACC-PROD']:
            logger.error(msg)
        else:
            logger.info(msg)
        return None
    if not password:
        msg = "Health process did not get a password for tenant {}; " \
              "returning from clean_up_apim_clients".format(tenant)
        if tenant in ['SD2E', 'TACC-PROD']:
            logger.error(msg)
        else:
            logger.info(msg)
        return None
    api_server = get_api_server(tenant)
    verify = get_tenant_verify(tenant)
    ag = Agave(api_server=api_server,
               username=username,
               password=password,
               verify=verify)
    logger.debug("health process created an ag for tenant: {}".format(tenant))
    try:
        cs = ag.clients.list()
        clients = cs.json()['result']
    except Exception as e:
        msg = "Health process got an exception trying to retrieve clients; exception: {}".format(
            e)
        logger.error(msg)
        return None
    for client in clients:
        # check if the name of the client is an abaco hash (i.e., a worker id). if not, we ignore it from the beginning
        name = client.get('name')
        if not is_hashid(name):
            logger.debug(
                "client {} is not an abaco hash id; skipping.".format(name))
            continue
        # we know this client came from a worker, so we need to check to see if the worker is still active;
        # first check if the worker even exists; if it does, the id will be the client name:
        worker = get_worker(name)
        if not worker:
            logger.info(
                "no worker associated with id: {}; deleting client.".format(
                    name))
            delete_client(ag, name)
            logger.info("client {} deleted by health process.".format(name))
            continue
        # if the worker exists, we should check the status:
        status = worker.get('status')
        if status == codes.ERROR:
            logger.info(
                "worker {} was in ERROR status so deleting client; worker: {}."
                .format(name, worker))
            delete_client(ag, name)
            logger.info("client {} deleted by health process.".format(name))
        else:
            logger.debug(
                "worker {} still active; not deleting client.".format(worker))
Ejemplo n.º 6
0
def check_nonce():
    """
    This function is an agaveflask authentication callback used to process the existence of a query parameter,
    x-nonce, an alternative authentication mechanism to JWT.
    
    When an x-nonce query parameter is provided, the request context is updated with the identity of the user owning
    the actor to which the nonce belongs. Note that the roles of said user will not be calculated so, in particular, 
    any privileged action cannot be taken via a nonce. 
    """
    logger.debug("top of check_nonce")
    # first check whether the request is even valid -
    if hasattr(request, 'url_rule'):
        logger.debug("request.url_rule: {}".format(request.url_rule))
        if hasattr(request.url_rule, 'rule'):
            logger.debug("url_rule.rule: {}".format(request.url_rule.rule))
        else:
            logger.info("url_rule has no rule.")
            raise ResourceError(
                "Invalid request: the API endpoint does not exist or the provided HTTP method is not allowed.",
                405)
    else:
        logger.info("Request has no url_rule")
        raise ResourceError(
            "Invalid request: the API endpoint does not exist or the provided HTTP method is not allowed.",
            405)
    try:
        nonce_id = request.args['x-nonce']
    except KeyError:
        raise PermissionsException("No JWT or nonce provided.")
    logger.debug("checking nonce with id: {}".format(nonce_id))
    # the nonce encodes the tenant in its id:
    g.tenant = Nonce.get_tenant_from_nonce_id(nonce_id)
    g.api_server = get_api_server(g.tenant)
    logger.debug(
        "tenant associated with nonce: {}; api_server assoicated with nonce: {}"
        .format(g.tenant, g.api_server))
    # get the actor_id base on the request path
    actor_id, actor_identifier = get_db_id()
    logger.debug("db_id: {}; actor_identifier: {}".format(
        actor_id, actor_identifier))
    level = required_level(request)

    # if the actor_identifier is an alias, then the nonce must be attached to that, so we must pass that in the
    # nonce check:
    if is_hashid(actor_identifier):
        Nonce.check_and_redeem_nonce(actor_id=actor_id,
                                     alias=None,
                                     nonce_id=nonce_id,
                                     level=level)
    else:
        alias_id = Alias.generate_alias_id(tenant=g.tenant,
                                           alias=actor_identifier)
        Nonce.check_and_redeem_nonce(actor_id=None,
                                     alias=alias_id,
                                     nonce_id=nonce_id,
                                     level=level)
    # if we were able to redeem the nonce, update auth context with the actor owner data:
    logger.debug("nonce valid and redeemed.")
    if is_hashid(actor_identifier):
        nonce = Nonce.get_nonce(actor_id=actor_id,
                                alias=None,
                                nonce_id=nonce_id)
    else:
        nonce = Nonce.get_nonce(actor_id=None,
                                alias=alias_id,
                                nonce_id=nonce_id)
    g.user = nonce.owner
    # update roles data with that stored on the nonce:
    g.roles = nonce.roles
    # now, manually call our authorization function:
    authorization()