Beispiel #1
0
def file_update_bucket(context, request):
    new_bucket = request.json_body.get('new_bucket')
    if not new_bucket:
        raise ValidationFailure('body', ['bucket'], 'New bucket not specified')
    force = asbool(request.params.get('force'))
    known_buckets = [
        request.registry.settings['file_upload_bucket'],
        request.registry.settings['pds_public_bucket'],
        request.registry.settings['pds_private_bucket'],
    ]
    # Try to validate input to a known bucket.
    if new_bucket not in known_buckets and not force:
        raise ValidationFailure('body', ['bucket'], 'Unknown bucket and force not specified')
    current_bucket = context._get_external_sheet().get('bucket')
    # Don't bother setting if already the same.
    if current_bucket != new_bucket:
        request.registry.notify(BeforeModified(context, request))
        context._set_external_sheet({'bucket': new_bucket})
        request.registry.notify(AfterModified(context, request))
    return {
        'status': 'success',
        '@type': ['result'],
        'old_bucket': current_bucket,
        'new_bucket': new_bucket
    }
Beispiel #2
0
def impersonate_user(context, request):
    """As an admin, impersonate a different user."""

    userid = request.validated['userid']
    users = request.registry[COLLECTIONS]['user']

    try:
        user = users[userid]
    except KeyError:
        raise ValidationFailure('body', ['userid'], 'User not found.')

    if user.properties.get('status') != 'current':
        raise ValidationFailure('body', ['userid'], 'User is not enabled.')

    user_properties = get_basic_properties_for_user(request, userid)
    # pop off impersonate user action if not admin
    user_properties['user_actions'] = [
        x for x in user_properties['user_actions']
        if (x['id'] and x['id'] != 'impersonate')
    ]
    # make a key
    registry = request.registry
    auth0_client = registry.settings.get('auth0.client')
    auth0_secret = registry.settings.get('auth0.secret')
    if not (auth0_client and auth0_secret):
        raise HTTPForbidden(title="No keys to impersonate user")

    jwt_contents = {
        'email': userid,
        'email_verified': True,
        'aud': auth0_client,
    }

    id_token = jwt.encode(jwt_contents,
                          auth0_secret,
                          algorithm=JWT_ENCODING_ALGORITHM)

    is_https = request.scheme == "https"

    request.response.set_cookie("jwtToken",
                                value=id_token.decode('utf-8'),
                                domain=request.domain,
                                path="/",
                                httponly=True,
                                samesite="strict",
                                overwrite=True,
                                secure=is_https)

    return user_properties
Beispiel #3
0
 def set_status(self, new_status, request, parent=True):
     root = find_root(self)
     schema = self.type_info.schema
     properties = self.upgrade_properties()
     item_id = '{}/'.format(resource_path(self))
     current_status = properties.get('status')
     if not current_status:
         raise ValidationFailure('body', ['status'], 'No property status')
     if not self._valid_status(new_status, schema, parent):
         return False
     force_transition = asbool(request.params.get('force_transition'))
     if not self._valid_transition(current_status, new_status, parent,
                                   force_transition):
         return False
     force_audit = asbool(request.params.get('force_audit'))
     self._block_on_audits(item_id, force_audit, request, parent,
                           new_status)
     update = asbool(request.params.get('update'))
     self._update_status(new_status, current_status, properties, schema,
                         request, item_id, update)
     request._set_status_considered_paths.add(
         (item_id, current_status, new_status))
     logging.warn('Considering {} from status {} to status {}'.format(
         item_id, current_status, new_status))
     block_children = self._calculate_block_children(
         request, force_transition)
     child_paths = self._get_child_paths(current_status, new_status,
                                         block_children)
     embedded_properties = request.embed(item_id, '@@embedded')
     related_objects = self._get_related_object(child_paths,
                                                embedded_properties,
                                                request)
     self._set_status_on_related_objects(new_status, related_objects, root,
                                         request)
     return True
Beispiel #4
0
 def _valid_status(new_status, schema, parent):
     valid_statuses = schema.get('properties', {}).get('status',
                                                       {}).get('enum', [])
     if new_status not in valid_statuses:
         if parent:
             msg = '{} not one of {}'.format(new_status, valid_statuses)
             raise ValidationFailure('body', ['status'], msg)
         else:
             return False
     return True
Beispiel #5
0
 def _valid_transition(current_status, new_status, parent,
                       force_transition):
     if current_status not in STATUS_TRANSITION_TABLE[
             new_status] and not force_transition:
         if parent:
             msg = 'Status transition {} to {} not allowed'.format(
                 current_status, new_status)
             raise ValidationFailure('body', ['status'], msg)
         else:
             return False
     return True
Beispiel #6
0
def item_set_status(context, request):
    new_status = request.json_body.get('status')
    if not new_status:
        raise ValidationFailure('body', ['status'], 'Status not specified')
    context.set_status(new_status, request)
    # Returns changed and considered lists of tuples: (item, current_status, new_status).
    return {
        'status': 'success',
        '@type': ['result'],
        'changed': request._set_status_changed_paths,
        'considered': request._set_status_considered_paths
    }
Beispiel #7
0
def impersonate_user(request):
    """As an admin, impersonate a different user."""
    userid = request.validated['userid']
    users = request.registry[COLLECTIONS]['user']

    try:
        user = users[userid]
    except KeyError:
        raise ValidationFailure('body', ['userid'], 'User not found.')

    if user.properties.get('status') != 'current':
        raise ValidationFailure('body', ['userid'], 'User is not enabled.')

    request.session.invalidate()
    request.session.get_csrf_token()
    request.response.headerlist.extend(remember(request, 'mailto.' + userid))
    user_properties = request.embed('/session-properties', as_user=userid)
    if 'auth.userid' in request.session:
        user_properties['auth.userid'] = request.session['auth.userid']

    return user_properties
 def disease_term_name(self, request, registry, disease_term_id=None):
     if disease_term_id is not None:
         term_name = list()
         for term_id in disease_term_id:
             if term_id in registry['ontology']:
                 term_name.append(registry['ontology'][term_id]['name'])
             else:
                 msg = 'Disease term ID {} is not a valid ID'.format(
                     term_id
                 )
                 raise ValidationFailure('body', ['disease_term_id'], msg)
         return term_name
Beispiel #9
0
def impersonate_user(request):
    """As an admin, impersonate a different user."""
    user = request.validated['user']

    try:
        user = find_resource(request.root, user)
    except KeyError:
        raise ValidationFailure('body', ['user'], 'User not found.')

    if user.item_type != 'user':
        raise ValidationFailure('body', ['user'], 'User not found.')
    if user.properties.get('status') != 'current':
        raise ValidationFailure('body', ['user'], 'User is not enabled.')

    request.session.invalidate()
    request.session.get_csrf_token()
    request.response.headerlist.extend(
        remember(request, 'mailto.%s' % user.uuid))
    user_properties = request.embed(
        '/session-properties', as_user=str(user.uuid))
    if 'auth.userid' in request.session:
        user_properties['auth.userid'] = request.session['auth.userid']

    return user_properties
Beispiel #10
0
 def _block_on_audits(item_id, force_audit, request, parent, new_status):
     if new_status not in ['released', 'submitted']:
         return
     if not parent or force_audit:
         return
     audits = request.embed(item_id, '@@audit')
     errors = audits.get('audit', {}).get('ERROR', [])
     not_compliants = audits.get('audit', {}).get('NOT_COMPLIANT', [])
     details = {
         detail.get('detail')
         for detail in itertools.chain(errors, not_compliants)
         if detail.get('detail')
     }
     if audits and any([errors, not_compliants]):
         raise ValidationFailure(
             'body', ['status'],
             'Audit on parent object. Must use ?force_audit=true to change status. {}'
             .format(list(details)))
Beispiel #11
0
 def organism(self, properties=None, return_uuid=False):
     if properties is None:
         properties = self.upgrade_properties()
     root = find_root(self)
     if 'target_organism' in properties:
         organism_uuid = properties['target_organism']
     else:
         organism_uuids = set(
             root.get_by_uuid(gene).upgrade_properties()['organism']
             for gene in properties['genes'])
         if len(organism_uuids) != 1:
             msg = 'Target genes are from different organisms: {}'.format(
                 repr(organism_uuids))
             raise ValidationFailure('body', ['genes'], msg)
         organism_uuid = next(iter(organism_uuids))
     if return_uuid:
         return organism_uuid
     return resource_path(root.get_by_uuid(organism_uuid), '')
Beispiel #12
0
    def create_and_commit(cls, request, properties, clean_headers=False):
        """
        Create a TrackingItem with a given request and properties, committing
        it directly to the DB. This works by manually committing the
        transaction, which may cause issues if this function is called as
        part of another POST. For this reason, this function should be used to
        track GET requests -- otherwise, use the standard POST method.
        If validator issues are hit, will not create the item but log to error

        Args:
            request: current request object
            properties (dict): TrackingItem properties to post
            clean_headers(bool): If True, remove 'Location' header created by POST

        Returns:
            dict response from snovault.crud_views.collection_add

        Raises:
            ValidationFailure if TrackingItem cannot be validated
        """
        collection = request.registry[COLLECTIONS]['TrackingItem']
        # set remote_user to standarize permissions
        prior_remote = request.remote_user
        request.remote_user = '******'
        # remove any missing attributes from DownloadTracking
        properties['download_tracking'] = {
            k: v
            for k, v in properties.get('download_tracking', {}).items()
            if v is not None
        }
        validate_request(collection.type_info.schema, request, properties)
        if request.errors:  # added from validate_request
            request.remote_user = prior_remote
            raise ValidationFailure('body', 'TrackingItem: create_and_commit',
                                    'Cannot validate request')
        ti_res = sno_collection_add(collection, request, False)  # render=False
        transaction.get().commit()
        if clean_headers and 'Location' in request.response.headers:
            del request.response.headers['Location']
        request.remote_user = prior_remote
        return ti_res
Beispiel #13
0
 def _validate_set_status_patch(request, schema, new_properties,
                                current_properties):
     validate_request(schema, request, new_properties, current_properties)
     if any(request.errors):
         raise ValidationFailure(request.errors)
Beispiel #14
0
def create_unauthorized_user(context, request):
    """
    Endpoint to create an unauthorized user, which will have no institution/project.
    Requires a reCAPTCHA response, which is propogated from the front end
    registration form. This is so the endpoint cannot be abused.
    Given a user properties in the request body, will validate those and also
    validate the reCAPTCHA response using the reCAPTCHA server. If all checks
    are succesful, POST a new user

    Args:
        request: Request object

    Returns:
        dictionary User creation response from collection_add

    Raises:
        LoginDenied, HTTPForbidden, or ValidationFailure
    """
    recaptcha_resp = request.json.get('g-recaptcha-response')
    if not recaptcha_resp:
        raise LoginDenied()

    email = request._auth0_authenticated  # equal to: jwt_info['email'].lower()
    user_props = request.json
    user_props_email = user_props.get("email", "<no e-mail supplied>").lower()
    if user_props_email != email:
        raise HTTPUnauthorized(
            title=
            "Provided email {} not validated with Auth0. Try logging in again."
            .format(user_props_email),
            headers={
                'WWW-Authenticate':
                "Bearer realm=\"{}\"; Basic realm=\"{}\"".format(
                    request.domain, request.domain)
            })

    del user_props['g-recaptcha-response']
    user_props['was_unauthorized'] = True
    user_props['email'] = user_props_email  # lowercased
    user_coll = request.registry[COLLECTIONS]['User']
    request.remote_user = '******'  # permission = restricted_fields

    # validate the User json
    validate_request(user_coll.type_info.schema, request, user_props)
    if request.errors:
        raise ValidationFailure('body', 'create_unauthorized_user',
                                'Cannot validate request')

    # validate recaptcha_resp
    # https://developers.google.com/recaptcha/docs/verify
    recap_url = 'https://www.google.com/recaptcha/api/siteverify'
    recap_values = {
        'secret': request.registry.settings['g.recaptcha.secret'],
        'response': recaptcha_resp
    }
    data = urlencode(recap_values).encode()
    headers = {
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8"
    }
    recap_res = requests.get(recap_url, params=data, headers=headers).json()

    if recap_res['success']:
        sno_res = sno_collection_add(user_coll, request, False)  # POST User
        if sno_res.get('status') == 'success':
            return sno_res
        else:
            raise HTTPForbidden(
                title="Could not create user. Try logging in again.")
    else:
        # error with re-captcha
        raise HTTPUnauthorized(
            title="Invalid reCAPTCHA. Try logging in again.",
            headers={
                'WWW-Authenticate':
                "Bearer realm=\"{}\"; Basic realm=\"{}\"".format(
                    request.domain, request.domain)
            })