def patch_change_ownership(self, manager_id: bson.ObjectId, patch: dict):
        """Shares or un-shares the Manager with a user."""

        man_man = current_flamenco.manager_manager
        if not man_man.user_is_owner(mngr_doc_id=manager_id):
            log.warning('User %s uses PATCH to (un)share manager %s, '
                        'but user is not owner of that Manager. Request denied.',
                        current_user_id(), manager_id)
            raise wz_exceptions.Forbidden()

        action = patch.get('action', '')
        try:
            action = man_man.ShareAction[action]
        except KeyError:
            raise wz_exceptions.BadRequest(f'Unknown action {action!r}')

        subject_uid = str2id(patch.get('user', ''))
        if action == man_man.ShareAction.share and subject_uid == current_user_id():
            log.warning('%s tries to %s Manager %s with itself',
                        current_user_id(), action, manager_id)
            raise wz_exceptions.BadRequest(f'Cannot share a Manager with yourself')

        if action == man_man.ShareAction.share and \
                not current_flamenco.auth.user_is_flamenco_user(subject_uid):
            log.warning('%s Manager %s on behalf of user %s, but subject user %s '
                        'is not Flamenco user', action, manager_id, current_user_id(),
                        subject_uid)
            raise wz_exceptions.Forbidden(f'User {subject_uid} is not allowed to use Flamenco')

        try:
            man_man.share_unshare_manager(manager_id, action, subject_uid)
        except ValueError as ex:
            raise wz_exceptions.BadRequest(str(ex))
Exemple #2
0
 def _check_related_permissions(self, obj):
     """Check permissions before deleting related Evidence or Document"""
     if not permissions.is_allowed_delete(
         obj.type, obj.id, obj.context_id) \
        and not permissions.has_conditions("delete", obj.type):
         raise wzg_exceptions.Forbidden()
     if not permissions.is_allowed_delete_for(obj):
         raise wzg_exceptions.Forbidden()
Exemple #3
0
def check_mapping_permissions(obj1, obj2):
    """Check is mapping allowed between objects"""
    error_message = "Mapping of this objects is not allowed"
    if isinstance(obj1, WithCustomRestrictions):
        if obj1.is_mapping_restricted(obj2):
            raise exceptions.Forbidden(description=error_message)

    if isinstance(obj2, WithCustomRestrictions):
        if obj2.is_mapping_restricted(obj1):
            raise exceptions.Forbidden(description=error_message)
Exemple #4
0
 def _authorize_github(self):
     """
     :rtype: None
     :raises werkzeug.exceptions.Forbidden: If cannot login to GitHub using `auth` credentials
     """
     self.github_api = GitHubApi(**self._auth)
     try:
         self.current_user = self.github_api.me()
     except gh_exc.AuthenticationFailed:
         raise exceptions.Forbidden()
     if self.current_user is None:
         raise exceptions.Forbidden()
Exemple #5
0
def check_put_access(request, lookup):
    """Only allow PUT to the current user, or all users if admin."""

    user = pillar.auth.get_current_user()
    if user.has_cap('admin'):
        return

    if user.is_anonymous:
        raise wz_exceptions.Forbidden()

    if str(lookup['_id']) != str(user.user_id):
        raise wz_exceptions.Forbidden()
Exemple #6
0
    def _assign_or_remove_project(self, manager_id: bson.ObjectId, patch: dict,
                                  action: str):
        """Assigns a manager to a project or removes it.

        The calling user must be owner of the manager (always)
        and member of the project (if assigning).
        """

        from pillar.api.projects.utils import user_rights_in_project

        from flamenco import current_flamenco

        try:
            project_strid = patch['project']
        except KeyError:
            log.warning('User %s sent invalid PATCH %r for manager %s.',
                        current_user_id(), patch, manager_id)
            raise wz_exceptions.BadRequest('Missing key "project"')

        project_id = str2id(project_strid)

        if not current_flamenco.manager_manager.user_is_owner(
                mngr_doc_id=manager_id):
            log.warning(
                'User %s uses PATCH to %s manager %s to/from project %s, '
                'but user is not owner of that Manager. Request denied.',
                current_user_id(), action, manager_id, project_id)
            raise wz_exceptions.Forbidden()

        # Removing from a project doesn't require project membership.
        if action != 'remove':
            methods = user_rights_in_project(project_id)
            if 'PUT' not in methods:
                log.warning(
                    'User %s uses PATCH to %s manager %s to/from project %s, '
                    'but only has %s rights on project. Request denied.',
                    current_user_id(), action, manager_id, project_id,
                    ', '.join(methods))
                raise wz_exceptions.Forbidden()

        log.info('User %s uses PATCH to %s manager %s to/from project %s',
                 current_user_id(), action, manager_id, project_id)

        ok = current_flamenco.manager_manager.api_assign_to_project(
            manager_id, project_id, action)
        if not ok:
            # Manager Manager will have already logged the cause.
            raise wz_exceptions.InternalServerError()
Exemple #7
0
def setup_for_flamenco(project: pillarsdk.Project):
    from pillar.api.utils import str2id
    import flamenco.setup

    project_id = project._id

    if not project.has_method('PUT'):
        log.warning(
            'User %s tries to set up project %s for Flamenco, but has no PUT rights.',
            current_user, project_id)
        raise wz_exceptions.Forbidden()

    if not current_flamenco.auth.current_user_is_flamenco_user():
        log.warning(
            'User %s tries to set up project %s for Flamenco, but is not flamenco-user.',
            current_user, project_id)
        raise wz_exceptions.Forbidden()

    log.info('User %s sets up project %s for Flamenco', current_user,
             project_id)
    flamenco.setup.setup_for_flamenco(project.url)

    # Find the Managers available to this user, so we can auto-assign if there is exactly one.
    man_man = current_flamenco.manager_manager
    managers = man_man.owned_managers(
        [bson.ObjectId(gid) for gid in current_user.groups])
    manager_count = managers.count()

    project_oid = str2id(project_id)
    user_id = current_user_id()

    if manager_count == 0:
        _, mngr_doc, _ = man_man.create_new_manager('My Manager', '', user_id)
        assign_man_oid = mngr_doc['_id']
        log.info(
            'Created and auto-assigning Manager %s to project %s upon setup for Flamenco.',
            assign_man_oid, project_oid)
        man_man.api_assign_to_project(assign_man_oid, project_oid, 'assign')

    elif manager_count == 1:
        assign_manager = managers.next()
        assign_man_oid = str2id(assign_manager['_id'])
        log.info(
            'Auto-assigning Manager %s to project %s upon setup for Flamenco.',
            assign_man_oid, project_oid)
        man_man.api_assign_to_project(assign_man_oid, project_oid, 'assign')

    return '', 204
Exemple #8
0
def assert_is_valid_patch(node_id, patch):
    """Raises an exception when the patch isn't valid."""

    try:
        op = patch['op']
    except KeyError:
        raise wz_exceptions.BadRequest("PATCH should have a key 'op' indicating the operation.")

    if op not in VALID_COMMENT_OPERATIONS:
        raise wz_exceptions.BadRequest('Operation should be one of %s',
                                       ', '.join(VALID_COMMENT_OPERATIONS))

    if op not in COMMENT_VOTING_OPS:
        # We can't check here, we need the node owner for that.
        return

    # See whether the user is allowed to patch
    if authorization.user_matches_roles(current_app.config['ROLES_FOR_COMMENT_VOTING']):
        log.debug('User is allowed to upvote/downvote comment')
        return

    # Access denied.
    log.info('User %s wants to PATCH comment node %s, but is not allowed.',
             authentication.current_user_id(), node_id)
    raise wz_exceptions.Forbidden()
Exemple #9
0
def proxy_search(request, url):
    found = False
    for allowed_host in g.db.query(ParcelSearchSource).filter_by(
            active=True).all():
        if url.startswith(allowed_host.url):
            found = True

    if not found:
        raise exceptions.Forbidden()

    headers = end_to_end_headers(request.headers)

    content_length = request.headers.get('content-length')
    if not content_length:
        data = None
    else:
        data = LimitedStream(request.stream)

    try:
        resp = requests.request(request.method,
                                url,
                                data=data,
                                headers=headers,
                                params=request.args,
                                stream=True)
        chunked_response = resp.headers.get('Transfer-Encoding') == 'chunked'
        line_based = resp.headers.get('Content-type', '').startswith(
            ('text/plain', 'application/json'))
    except requests.exceptions.RequestException, ex:
        raise exceptions.BadGateway('source returned: %s' % ex)
Exemple #10
0
def oauth_callback(provider):
    if current_user.is_authenticated:
        return redirect(url_for('main.homepage'))

    oauth = OAuthSignIn.get_provider(provider)
    try:
        oauth_user = oauth.callback()
    except OAuthCodeNotProvided as e:
        log.error(e)
        raise wz_exceptions.Forbidden()
    if oauth_user.id is None:
        log.debug('Authentication failed for user with {}'.format(provider))
        return redirect(url_for('main.homepage'))

    # Find or create user
    user_info = {'id': oauth_user.id, 'email': oauth_user.email, 'full_name': ''}
    db_user = find_user_in_db(user_info, provider=provider)
    db_id, status = upsert_user(db_user)
    token = generate_and_store_token(db_id)

    # Login user
    pillar.auth.login_user(token['token'], load_from_db=True)

    if provider == 'blender-id' and current_user.is_authenticated:
        # Check with Blender ID to update certain user roles.
        update_subscription()

    next_after_login = session.pop('next_after_login', None)
    if next_after_login:
        log.debug('Redirecting user to %s', next_after_login)
        return redirect(next_after_login)
    return redirect(url_for('main.homepage'))
    def patch_requeue(self, task_id: bson.ObjectId, patch: dict):
        """Re-queue a task and its successors."""

        from flamenco import current_flamenco
        from pillar.api.utils.authentication import current_user_id

        tasks_coll = current_flamenco.db('tasks')
        task = tasks_coll.find_one({'_id': task_id},
                                   projection={
                                       'job': 1,
                                       'manager': 1
                                   })

        if not current_flamenco.manager_manager.user_may_use(
                mngr_doc_id=task['manager']):
            log.warning(
                'patch_set_task_status(%s, %r): User %s is not allowed to use manager %s!',
                task_id, patch, current_user_id(), task['manager'])
            raise wz_exceptions.Forbidden()

        current_flamenco.task_manager.api_requeue_task_and_successors(task_id)

        # Also inspect other tasks of the same job, and possibly update the job status as well.
        current_flamenco.job_manager.update_job_after_task_status_change(
            task['job'], task_id, 'queued')
Exemple #12
0
def handle_export_post(**kwargs):
  """Handle export post"""
  check_import_export_headers()
  request_json = request.json
  objects = request_json.get("objects")
  exportable_objects = request_json.get("exportable_objects", [])
  current_time = request.json.get("current_time")
  user = login.get_current_user()
  if user.system_wide_role == 'No Access':
    raise wzg_exceptions.Forbidden()
  if not objects or not current_time:
    raise wzg_exceptions.BadRequest(
        app_errors.INCORRECT_REQUEST_DATA.format(job_type="Export"))
  try:
    filename = import_helper.get_export_filename(objects,
                                                 current_time,
                                                 exportable_objects)
    ie = import_export.create_import_export_entry(
        job_type="Export",
        status="In Progress",
        title=filename,
        start_at=datetime.utcnow(),
    )
    run_background_export(ie.id, objects, exportable_objects)
    return make_import_export_response(ie.log_json())
  except Exception as e:
    logger.exception(e.message)
    raise wzg_exceptions.BadRequest(
        app_errors.INCORRECT_REQUEST_DATA.format(job_type="Export"))
Exemple #13
0
def remove_file(full_path: str = ''):
    abspath = os.path.join(HOME_PATH, full_path)

    if not (os.path.exists(abspath)):
        raise wexs.BadRequest()

    try:
        if (os.path.isfile(abspath)):
            absdir = os.path.dirname(full_path)
            os.remove(abspath)
            return redirect(url_for('index', varargs=absdir))

        elif (os.path.isdir(abspath)):
            abspath = abspath.replace('/', os.sep)

            cmd = f'rmdir /Q /S "{abspath}"'
            code = os.system(cmd)

            assert code == 0, f'Process returned with code {code}. Failed to remove folder'

            parent = os.path.join(full_path, os.pardir)
            parent = os.path.normpath(parent)

            return redirect(url_for('index', varargs=parent))

        else:
            raise OSError('Path is neither a file nor directory')

    except OSError as e:
        raise wexs.Forbidden(e)

    except AssertionError as e:
        raise wexs.BadRequest(e)

    raise wexs.BadRequest('Unknown error!')
Exemple #14
0
def check_job_permission_fetch_resource(response):
    from functools import lru_cache

    if current_flamenco.auth.current_user_is_flamenco_admin():
        return

    if not current_flamenco.manager_manager.user_is_manager():
        # Subscribers can read Flamenco jobs.
        if current_user.has_cap('flamenco-view'):
            return
        raise wz_exceptions.Forbidden()

    @lru_cache(32)
    def user_managers(mngr_doc_id):
        return current_flamenco.manager_manager.user_manages(mngr_doc_id=mngr_doc_id)

    items = response['_items']
    to_remove = []
    for idx, job_doc in enumerate(items):
        if not user_managers(job_doc.get('manager')):
            to_remove.append(idx)

    for idx in reversed(to_remove):
        del items[idx]

    response['_meta']['total'] -= len(items)
Exemple #15
0
        def wrapper(project_url, *args, **kwargs):
            if isinstance(project_url, pillarsdk.Resource):
                # This is already a resource, so this call probably is from one
                # view to another. Assume the caller knows what he's doing and
                # just pass everything along.
                return wrapped(project_url, *args, **kwargs)

            api = pillar_api()

            project = pillarsdk.Project.find_by_url(
                project_url, {'projection': projections}, api=api)

            is_flamenco = current_flamenco.is_flamenco_project(project)
            if not is_flamenco:
                return error_project_not_setup_for_flamenco(project)

            session['flamenco_last_project'] = project.to_dict()

            project_id = bson.ObjectId(project['_id'])
            auth = current_flamenco.auth
            if not auth.current_user_may(action, project_id):
                if current_user.is_anonymous:
                    raise wz_exceptions.Forbidden(
                        'Login required for this URL')
                log.info('Denying user %s access %s to Flamenco on project %s',
                         flask_login.current_user, action, project_id)
                return error_project_not_available()

            if extension_props:
                pprops = project.extension_props.flamenco
                return wrapped(project, pprops, *args, **kwargs)
            return wrapped(project, *args, **kwargs)
    def post(self):

        args = parser.parse(self.post_args, request)

        username, password = args['username'], args['password']

        user = db.session.query(User) \
            .filter(User.username == username) \
            .filter(User.deleted.isnot(True)) \
            .options(joinedload(User.roles)) \
            .one_or_none()

        if user is None:
            raise exc.NotFound('User with this username does not exist')

        is_password_valid = User.check_password(user.password_md5, password)
        if not is_password_valid:
            current_app.logger.warning(f'user_email={args["username"]} '
                                       f'has failed to log in')
            raise exc.Forbidden('Invalid password')

        current_app.logger.debug(f'user_email={args["username"]} has logged in')

        token = generate_refresh_token(user)
        refresh_token = RefreshToken(token=token, user_id=user.id)
        db.session.add(refresh_token)
        db.session.commit()

        user_serializer = UserAuthSerializer()
        user.refresh_token = token
        user_data = user_serializer.dump(user)

        return jsonify(user_data.data)
Exemple #17
0
    def related_objects(self, id):
        """Get data for snapshot related_objects page."""
        # id name is used as a kw argument and can't be changed here
        # pylint: disable=invalid-name,redefined-builtin
        from ggrc import models
        from ggrc.rbac import permissions
        snapshot = models.Snapshot.query.get(id)
        if snapshot is None:
            return self.not_found_response()
        if not permissions.is_allowed_read_for(snapshot):
            raise exceptions.Forbidden()

        data = defaultdict(list)
        for obj in snapshot.related_objects():
            obj_data = _stub(obj)
            if obj.type == "Snapshot":
                child = referenced_objects.get(obj.child_type, obj.child_id)
                obj_data.update({
                    "child": _stub(child),
                    "revision:": {
                        "content": {
                            "title":
                            obj.revision.content.get("title", ""),
                            "updated_at":
                            obj.revision.content.get("updated_at", "")
                        }
                    }
                })
            data[obj.type].append(obj_data)
        return self.json_success_response(data, )
Exemple #18
0
def view_job(project, flamenco_props, job_id):
    if not request.is_xhr:
        return for_project(project, job_id=job_id)

    # Job list is public, job details are not.
    if not current_user.has_cap('flamenco-view'):
        raise wz_exceptions.Forbidden()

    from .sdk import Job
    from ..managers.sdk import Manager

    api = pillar_api()
    job = Job.find(job_id, api=api)

    try:
        manager = Manager.find(job.manager, api=api)
    except pillarsdk.ForbiddenAccess:
        # It's very possible that the user doesn't have access to this Manager.
        manager = None
    except pillarsdk.ResourceNotFound:
        log.warning('Flamenco job %s has a non-existant manager %s', job_id,
                    job.manager)
        manager = None

    from . import (CANCELABLE_JOB_STATES, REQUEABLE_JOB_STATES,
                   RECREATABLE_JOB_STATES, ARCHIVE_JOB_STATES,
                   ARCHIVEABLE_JOB_STATES, FAILED_TASKS_REQUEABLE_JOB_STATES)

    auth = current_flamenco.auth
    write_access = auth.current_user_may(auth.Actions.USE,
                                         bson.ObjectId(project['_id']))

    status = job['status']
    is_archived = status in ARCHIVE_JOB_STATES
    archive_available = is_archived and job.archive_blob_name

    # Sort job settings so we can iterate over them in a deterministic way.
    job_settings = collections.OrderedDict(
        (key, job.settings[key])
        for key in sorted(job.settings.to_dict().keys()))

    return render_template(
        'flamenco/jobs/view_job_embed.html',
        job=job,
        manager=manager,
        project=project,
        flamenco_props=flamenco_props.to_dict(),
        flamenco_context=request.args.get('context'),
        can_cancel_job=write_access and status in CANCELABLE_JOB_STATES,
        can_requeue_job=write_access and status in REQUEABLE_JOB_STATES,
        can_recreate_job=write_access and status in RECREATABLE_JOB_STATES,
        can_archive_job=write_access and status in ARCHIVEABLE_JOB_STATES,
        # TODO(Sybren): check that there are actually failed tasks before setting to True:
        can_requeue_failed_tasks=write_access
        and status in FAILED_TASKS_REQUEABLE_JOB_STATES,
        is_archived=is_archived,
        write_access=write_access,
        archive_available=archive_available,
        job_settings=job_settings,
    )
Exemple #19
0
def render_category(category='', template=None):
    """ Render a category page.

    Arguments:

    category -- The category to render
    template -- The template to render it with
    """
    # pylint:disable=too-many-return-statements

    # See if this is an aliased path
    redir = get_redirect()
    if redir:
        return redir

    # Forbidden template types
    if template and template.startswith('_'):
        raise http_error.Forbidden("Template is private")
    if template in ['entry', 'error']:
        raise http_error.BadRequest("Invalid view requested")

    if category:
        # See if there's any entries for the view...
        if not orm.select(e for e in model.Entry if e.category == category or
                          e.category.startswith(category + '/')):
            raise http_error.NotFound("No such category")

    if not template:
        template = Category(category).get('Index-Template') or 'index'

    tmpl = map_template(category, template)

    if not tmpl:
        # this might actually be a malformed category URL
        test_path = '/'.join((category, template)) if category else template
        LOGGER.debug("Checking for malformed category %s", test_path)
        record = orm.select(
            e for e in model.Entry if e.category == test_path).exists()
        if record:
            return redirect(url_for('category', category=test_path, **request.args))

        # nope, we just don't know what this is
        raise http_error.NotFound(
            "No such view '{template}'".format(template=template))

    view_spec = view.parse_view_spec(request.args)
    view_spec['category'] = category
    view_obj = view.View(view_spec)

    rendered, etag = render_publ_template(
        tmpl,
        _url_root=request.url_root,
        category=Category(category),
        view=view_obj)

    if request.if_none_match.contains(etag):
        return 'Not modified', 304

    return rendered, {'Content-Type': mime_type(tmpl),
                      'ETag': etag}
Exemple #20
0
def portfolio_download(human_id, filename):
    logger.debug('GET ' + request.url)
    try:
        # Find the portfolio
        folio = data_engine.get_portfolio(human_id=human_id)
        if not folio:
            raise DoesNotExistError('Portfolio \'%s\' does not exist' %
                                    human_id)

        # Ensure that the user has permission to download the portfolio
        user = get_session_user()
        permissions_engine.ensure_portfolio_permitted(
            folio, FolioPermission.ACCESS_DOWNLOAD, user)

        # Check that the filename is valid (note: assumes folio.downloads is eager loaded)
        if not filename:
            raise DoesNotExistError('No filename specified')
        folio_exports = [
            dl for dl in folio.downloads if dl.filename == filename
        ]
        if not folio_exports:
            raise DoesNotExistError('Download \'%s\' is not available' %
                                    filename)
        folio_export = folio_exports[0]
        # The physical file should always exist when the data+filename exists
        # This also checks that the file path lies inside IMAGES_BASE_DIR
        zip_path = get_portfolio_export_file_path(folio_export)
        ensure_path_exists(zip_path, require_file=True)

        # Prepare to serve the file
        response = send_file(
            get_abs_path(zip_path),
            mimetype='application/zip',
            as_attachment=True,
            conditional=True,
            cache_timeout=31536000  # zips never change once created
        )

        # Lastly write an audit record
        data_engine.add_portfolio_history(folio, user,
                                          FolioHistory.ACTION_DOWNLOADED,
                                          folio_export.filename)
        return response

    except httpexc.HTTPException:
        # Pass through HTTP 4xx and 5xx
        raise
    except SecurityError as e:
        if app.config['DEBUG']:
            raise
        log_security_error(e, request)
        raise httpexc.Forbidden()
    except DoesNotExistError as e:
        logger.warning('404 Not found: ' + str(e))
        raise httpexc.NotFound(safe_error_str(e))
    except Exception as e:
        if app.config['DEBUG']:
            raise
        logger.error('500 Error for ' + request.url + '\n' + str(e))
        raise httpexc.InternalServerError(safe_error_str(e))
Exemple #21
0
def view_task(project, flamenco_props, task_id):
    from flamenco.tasks.sdk import Task

    api = pillar_api()

    if not request.is_xhr:
        # Render page that'll perform the XHR.
        from flamenco.jobs import routes as job_routes

        task = Task.find(task_id, {'projection': {'job': 1}}, api=api)
        return job_routes.for_project(project,
                                      job_id=task['job'],
                                      task_id=task_id)

    # Task list is public, task details are not.
    if not current_user.has_cap('flamenco-view'):
        raise wz_exceptions.Forbidden()

    task = Task.find(task_id, api=api)

    from . import REQUEABLE_TASK_STATES
    project_id = bson.ObjectId(project['_id'])

    write_access = current_flamenco.auth.current_user_may(
        Actions.USE, project_id)
    can_requeue_task = write_access and task['status'] in REQUEABLE_TASK_STATES

    return render_template('flamenco/tasks/view_task_embed.html',
                           task=task,
                           project=project,
                           flamenco_props=flamenco_props.to_dict(),
                           flamenco_context=request.args.get('context'),
                           can_view_log=write_access,
                           can_requeue_task=can_requeue_task)
Exemple #22
0
    def by_bank(self, project):
        if not http.request.env.user.sudo(http.request.env.user). \
                user_has_groups(
                    'bestja_project_hierarchy.managers_level0,bestja_project_hierarchy.managers_level1'
                ):
            return exceptions.Forbidden()

        http.request.env.cr.execute(
            """
            SELECT responsible.id, responsible.name, SUM(entry.total_cities_nr) as cities_nr,
                SUM(entry.tonnage) as sum_tonnage
            FROM bestja_report_entry as entry
            JOIN organization as responsible ON (entry.responsible_organization = responsible.id)
            JOIN bestja_detailed_report as report ON (entry.detailed_report = report.id)
            WHERE entry.top_project = %s AND report.state = 'accepted'
            GROUP BY responsible.id, responsible.name
            ORDER BY sum_tonnage DESC, responsible.name ASC
        """, [
                project,
            ])
        bank_sums = http.request.env.cr.fetchall()

        return http.request.render(
            'bestja_detailed_reports.by_bank', {
                'project':
                http.request.env['bestja.project'].sudo().browse([
                    project,
                ]),
                'bank_sums':
                bank_sums,
            })
    def patch_set_task_status(self, task_id: bson.ObjectId, patch: dict):
        """Updates a task's status in the database."""

        from flamenco import current_flamenco
        from pillar.api.utils.authentication import current_user_id

        tasks_coll = current_flamenco.db('tasks')
        task = tasks_coll.find_one({'_id': task_id},
                                   projection={
                                       'job': 1,
                                       'manager': 1,
                                       'status': 1
                                   })

        if not current_flamenco.manager_manager.user_may_use(
                mngr_doc_id=task['manager']):
            log.warning(
                'patch_set_task_status(%s, %r): User %s is not allowed to use manager %s!',
                task_id, patch, current_user_id(), task['manager'])
            raise wz_exceptions.Forbidden()

        new_status = patch['status']
        try:
            current_flamenco.task_manager.api_set_task_status(task, new_status)
        except ValueError:
            raise wz_exceptions.UnprocessableEntity('Invalid status')
Exemple #24
0
    def projects_list(self):
        user_bank_id = None
        if not http.request.env.user.sudo(http.request.env.user). \
                user_has_groups(
                    'bestja_project_hierarchy.managers_level0,bestja_project_hierarchy.managers_level1'
                ):
            user_organization = http.request.env['organization'].sudo().search(
                [
                    ('level', '=', 2),
                    '|',  # noqa
                    ('coordinator', '=', http.request.env.user.id),
                    ('projects.manager', '=', http.request.env.user.id)
                ])
            if not user_organization:
                return exceptions.Forbidden()
            user_bank_id = user_organization.parent.id

        projects = http.request.env['bestja.project'].sudo().search(
            [
                ('organization_level', '=', 0),
                ('use_detailed_reports', '=', True),
                ('date_start', '<=', Date.today()),
            ],
            order='date_start desc')

        return http.request.render('bestja_detailed_reports.projects_list', {
            'projects': projects,
            'user_bank_id': user_bank_id,
        })
Exemple #25
0
def authenticate_account(request, number):
    """
    Authenticates the account and raises error
    :param request: contains input parameter
    :param number: number belonging to some account
    :return: Error in case authentication fails
    """

    error = None
    username = request.get('username', None)
    auth_id = request.get('password', None)

    # authenticate the request
    account_obj = Account.query.filter_by(auth_id=auth_id,
                                          username=username).first()
    if not account_obj:
        raise exceptions.Forbidden()

    # check if number belongs to the particular account
    number_object = phone_number.query.filter_by(
        number=number, account_id=account_obj.id).first()
    if not number_object:
        error = "%s parameter not found"

    return error
Exemple #26
0
def view_task(project, flamenco_props, task_id):
    if not request.is_xhr:
        return for_project(project, task_id=task_id)

    # Task list is public, task details are not.
    if not flask_login.current_user.has_role(*ROLES_REQUIRED_TO_VIEW_ITEMS):
        raise wz_exceptions.Forbidden()

    api = pillar_api()
    task = pillarsdk.Node.find(task_id, api=api)
    node_type = project.get_node_type(node_type_task['name'])

    # Fetch project users so that we can assign them tasks
    if 'PUT' in task.allowed_methods:
        users = project.get_users(api=api)
        project.users = users['_items']
    else:
        task.properties.assigned_to.users = [
            pillar.web.subquery.get_user_info(uid)
            for uid in task.properties.assigned_to.users
        ]

    return render_template('flamenco/tasks/view_task_embed.html',
                           task=task,
                           project=project,
                           task_node_type=node_type,
                           flamenco_props=flamenco_props.to_dict(),
                           flamenco_context=request.args.get('context'))
Exemple #27
0
def revoke_auth_token(manager_id):
    """Revokes the Manager's existing authentication tokens.

    Only allowed by owners of the Manager.
    """

    manager_oid = str2id(manager_id)

    csrf = request.form.get('csrf', '')
    if not flask_wtf.csrf.validate_csrf(csrf):
        log.warning(
            'User %s tried to generate authentication token for Manager %s without '
            'valid CSRF token!', current_user.user_id, manager_oid)
        raise wz_exceptions.PreconditionFailed()

    if not current_flamenco.manager_manager.user_is_owner(
            mngr_doc_id=manager_oid):
        log.warning(
            'User %s wants to generate authentication token of manager %s, '
            'but user is not owner of that Manager. Request denied.',
            current_user.user_id, manager_oid)
        raise wz_exceptions.Forbidden()

    current_flamenco.manager_manager.revoke_auth_token(manager_oid)
    return '', 204
Exemple #28
0
def ValidateCSRFTokenOrRaise(request):
    """Decorator for WSGI handler that checks CSRF cookie against the request."""

    # CSRF check doesn't make sense for GET/HEAD methods, because they can
    # (and are) used when downloading files through <a href> links - and
    # there's no way to set X-CSRFToken header in this case.
    if request.method in ("GET", "HEAD"):
        return

    # In the ideal world only JavaScript can be used to add a custom header, and
    # only within its origin. By default, browsers don't allow JavaScript to
    # make cross origin requests.
    #
    # Unfortunately, in the real world due to bugs in browsers plugins, it can't
    # be guaranteed that a page won't set an HTTP request with a custom header
    # set. That's why we also check the contents of a header via an HMAC check
    # with a server-stored secret.
    #
    # See for more details:
    # https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
    # (Protecting REST Services: Use of Custom Request Headers).
    csrf_token = utils.SmartStr(request.headers.get("X-CSRFToken", ""))
    if not csrf_token:
        logging.info("Did not find headers CSRF token for: %s", request.path)
        raise werkzeug_exceptions.Forbidden("CSRF token is missing")

    try:
        decoded = base64.urlsafe_b64decode(csrf_token + "==")
        digest, token_time = decoded.rsplit(CSRF_DELIMITER, 1)
        token_time = long(token_time)
    except (TypeError, ValueError):
        logging.info("Malformed CSRF token for: %s", request.path)
        raise werkzeug_exceptions.Forbidden("Malformed CSRF token")

    if len(digest) != hashlib.sha256().digest_size:
        logging.info("Invalid digest size for: %s", request.path)
        raise werkzeug_exceptions.Forbidden("Malformed CSRF token digest")

    expected = GenerateCSRFToken(request.user, token_time)
    if not constant_time.bytes_eq(csrf_token, expected):
        logging.info("Non-matching CSRF token for: %s", request.path)
        raise werkzeug_exceptions.Forbidden("Non-matching CSRF token")

    current_time = rdfvalue.RDFDatetime.Now().AsMicrosecondsSinceEpoch()
    if current_time - token_time > CSRF_TOKEN_DURATION.microseconds:
        logging.info("Expired CSRF token for: %s", request.path)
        raise werkzeug_exceptions.Forbidden("Expired CSRF token")
Exemple #29
0
    def _HandleHelp(self, request):
        """Handles help requests."""
        help_path = request.path.split("/", 2)[-1]
        if not help_path:
            raise werkzeug_exceptions.Forbidden("Error: Invalid help path.")

        # Proxy remote documentation.
        return self._RedirectToRemoteHelp(help_path)
Exemple #30
0
def present_notifications():
    """Present proposal notifications."""
    if not rbac.permissions.is_admin():
        raise exceptions.Forbidden()
    proposals = get_email_proposal_list()
    generator = ("<h1> email to {}</h1>\n {}".format(addressee.email, body)
                 for addressee, body in addressee_body_generator(proposals))
    return "".join(generator)