Beispiel #1
0
    def get_default_where_clauses(
            self,
            context: IBaseObject,
            unrestricted: bool = False) -> typing.List[str]:
        clauses = []
        sql_wheres = []
        if unrestricted is False:
            users = []
            principal = get_authenticated_user()
            if principal is None:
                # assume anonymous then
                principal = AnonymousUser()

            users.append(principal.id)
            users.extend(principal.groups)
            roles = get_roles_principal(context)

            clauses.extend([
                "json->'access_users' ?| array['{}']".format("','".join(
                    [sqlq(u) for u in users])),
                "json->'access_roles' ?| array['{}']".format("','".join(
                    [sqlq(r) for r in roles])),
            ])
            sql_wheres.append("({})".format(" OR ".join(clauses)))
        container = find_container(context)
        if container is None:
            raise ContainerNotFound()

        sql_wheres.append(
            f"""json->>'container_id' = '{sqlq(container.id)}'""")
        sql_wheres.append("""type != 'Container'""")
        sql_wheres.append(f"""parent_id != '{sqlq(TRASHED_ID)}'""")
        return sql_wheres
Beispiel #2
0
    async def __call__(self):
        user = get_authenticated_user()
        self.policy = get_security_policy(user)
        definition = copy.deepcopy(
            app_settings["swagger"]["base_configuration"])
        vhm = self.request.headers.get("X-VirtualHost-Monster")
        if vhm:
            parsed_url = urlparse(vhm)
            definition["host"] = parsed_url.netloc
            definition["schemes"] = [parsed_url.scheme]
            definition["basePath"] = parsed_url.path
        else:
            definition["host"] = self.request.host
            definition["schemes"] = [get_request_scheme(self.request)]
        if 'version' not in definition['info']:
            definition["info"]["version"] = pkg_resources.get_distribution(
                "guillotina").version

        api_defs = app_settings["api_definition"]

        path = get_full_content_path(self.context)

        for dotted_iface in api_defs.keys():
            iface = resolve_dotted_name(dotted_iface)
            if iface.providedBy(self.context):
                iface_conf = api_defs[dotted_iface]
                self.get_endpoints(iface_conf, path, definition["paths"])

        definition["definitions"] = app_settings["json_schema_definitions"]
        return definition
Beispiel #3
0
    async def __call__(self):
        allowed = app_settings.get("allow_register", False)
        if allowed is False:
            raise HTTPUnauthorized(content={"text": "Not allowed registration"})

        validator = RecaptchaValidator()
        status = await validator.validate()
        if status is False:
            raise HTTPUnauthorized(content={"text": "Invalid validation"})

        payload = await self.request.json()

        user_id = payload.get("id", None)
        user = await find_user({"id": user_id})
        if user is not None:
            raise HTTPUnauthorized(content={"text": "Invalid login"})

        validation_utility = get_utility(IAuthValidationUtility)
        if validation_utility is not None:
            redirect_url = self.request.query.get("redirect_url", None)
            username = payload.get("fullname", payload.get("id", ""))
            task_description = f"Registering user {username}"
            actual_user = get_authenticated_user()
            await validation_utility.start(
                as_user=payload.get("id"),
                from_user=actual_user.id,
                task_description=task_description,
                task_id="register_user",
                email=payload.get("email"),
                context_description=self.context.title,
                redirect_url=redirect_url,
                data=payload,
            )
        else:
            raise HTTPNotAcceptable()
Beispiel #4
0
    def get_default_where_clauses(self,
                                  container: IContainer) -> typing.List[str]:
        users = []
        roles = []
        principal = get_authenticated_user()
        if principal is None:
            # assume anonymous then
            principal = AnonymousUser()
        policy = get_security_policy(principal)

        users.append(principal.id)
        users.extend(principal.groups)
        roles_dict = policy.global_principal_roles(principal.id,
                                                   principal.groups)
        roles.extend([key for key, value in roles_dict.items() if value])

        clauses = [
            "json->'access_users' ?| array['{}']".format("','".join(
                [sqlq(u) for u in users])),
            "json->'access_roles' ?| array['{}']".format("','".join(
                [sqlq(r) for r in roles])),
        ]
        sql_wheres = ["({})".format(" OR ".join(clauses))]
        sql_wheres.append(
            f"""json->>'container_id' = '{sqlq(container.id)}'""")
        sql_wheres.append("""type != 'Container'""")
        sql_wheres.append(f"""parent_id != '{sqlq(TRASHED_ID)}'""")
        return sql_wheres
async def build_security_query(container):
    # The users who has plone.AccessContent permission by prinperm
    # The roles who has plone.AccessContent permission by roleperm
    users = []
    roles = []
    user = get_authenticated_user()
    policy = get_security_policy(user)

    users.append(user.id)
    users.extend(user.groups)

    roles_dict = policy.global_principal_roles(user.id, user.groups)
    roles.extend([key for key, value in roles_dict.items() if value])

    # We got all users and roles
    # users: users and groups

    should_list = [{"match": {"access_roles": x}} for x in roles]
    should_list.extend([{"match": {"access_users": x}} for x in users])

    return {
        "query": {
            "bool": {
                "filter": [{
                    "bool": {
                        "should": should_list,
                        "minimum_should_match": 1
                    }
                }]
            }
        }
    }
Beispiel #6
0
async def test_deny_inherit_accesscontent(container_requester):
    async with container_requester as requester:
        response, status = await requester(
            "POST",
            "/db/guillotina/@sharing",
            data=json.dumps({
                "prinperm": [{
                    "principal": "Anonymous User",
                    "permission": "guillotina.AccessContent",
                    "setting": "Allow",
                }]
            }),
        )
        assert status == 200

        # The owner of item 'testing' is 'root'
        response, status = await requester(
            "POST",
            "/db/guillotina/",
            data=json.dumps({
                "@type": "Item",
                "id": "testing"
            }),
        )
        assert status == 201

        # Only the owner of the object can do AccessContent
        response, status = await requester(
            "POST",
            "/db/guillotina/testing/@sharing",
            data=json.dumps({
                "perminhe": [{
                    "permission": "guillotina.AccessContent",
                    "setting": "Deny"
                }],
                "roleperm": [{
                    "permission": "guillotina.AccessContent",
                    "role": "guillotina.Owner",
                    "setting": "Allow",
                }],
            }),
        )
        assert status == 200

        response, status = await requester(
            "GET", "/db/guillotina/testing/@all_permissions")
        assert status == 200

        container = await utils.get_container(requester=requester)
        content = await container.async_get("testing")

        policy = get_security_policy()
        assert get_authenticated_user() is None  # Anonymous

        # Anonymous user has access to container...
        assert policy.check_permission("guillotina.AccessContent", container)
        # ...but doesn't has access to the item 'testing'
        assert not policy.check_permission("guillotina.AccessContent", content)
Beispiel #7
0
    async def __call__(self):
        user_id: str = self.request.matchdict["user"]
        actual_user = get_authenticated_user()
        if actual_user.id == user_id:
            # Self setting password
            # Payload : {
            #   'old_password': '******',
            #   'new_password': '******',
            # }

            data = await self.request.json()
            try:
                await actual_user.set_password(
                    data.get("new_password", None), old_password=data.get("old_password", None)
                )
            except AttributeError:
                raise HTTPNotAcceptable()
        else:
            # We validate with recaptcha
            validator = RecaptchaValidator()
            status = await validator.validate()
            if status is False:
                raise HTTPUnauthorized(content={"text": "Invalid validation"})

            # We need to validate is a valid user
            user = await find_user({"id": user_id})

            if user is None:
                raise HTTPUnauthorized(content={"text": "Invalid operation"})

            # We need to validate is a valid user
            try:
                email = user.properties.get("email", user.email)
            except AttributeError:
                email = None
            if email is None and "@" in user_id:
                email = user_id

            if email is None:
                raise HTTPPreconditionFailed(content={"reason": "User without mail configured"})

            # We need to generate a token and send to user email
            validation_utility = get_utility(IAuthValidationUtility)
            if validation_utility is not None:
                redirect_url = self.request.query.get("redirect_url", None)
                await validation_utility.start(
                    as_user=user_id,
                    from_user=actual_user.id,
                    email=email,
                    task_description="Reset password",
                    task_id="reset_password",
                    context_description=self.context.title,
                    redirect_url=redirect_url,
                )
            else:
                raise HTTPNotAcceptable()
Beispiel #8
0
 async def __call__(self):
     user = get_authenticated_user()
     session_manager = query_utility(ISessionManagerUtility)
     if session_manager is not None:
         try:
             await session_manager.drop_session(user.id, user._v_session)
         except AttributeError:
             raise HTTPPreconditionFailed("Session manager configured but no session on jwt")
     else:
         raise HTTPNotAcceptable()
Beispiel #9
0
 async def __aenter__(self):
     self.old_request = task_vars.request.get()
     self.old_db = task_vars.db.get()
     self.old_tm = task_vars.tm.get()
     self.old_user = get_authenticated_user()
     self.request = get_mocked_request()
     task_vars.db.set(self.db)
     self.tm = self.db.get_transaction_manager()
     task_vars.tm.set(self.tm)
     set_authenticated_user(self.user)
     return self
Beispiel #10
0
    async def __call__(self):
        user = get_authenticated_user()
        user_id: str = self.request.matchdict["user"]
        if user.id != user_id:
            raise HTTPUnauthorized()

        session_manager = query_utility(ISessionManagerUtility)
        if session_manager is not None:
            return await session_manager.list_sessions(user.id)
        else:
            raise HTTPNotAcceptable()
Beispiel #11
0
    async def __call__(self):
        user = get_authenticated_user(self.request)
        if user is None:
            return HTTPUnauthorized(content={'reason': 'user not authorized'})

        data = {
            'exp': datetime.utcnow() + timedelta(seconds=self.token_timeout),
            'id': user.id
        }
        jwt_token = jwt.encode(data,
                               app_settings['jwt']['secret']).decode('utf-8')
        return {'exp': data['exp'], 'token': jwt_token}
Beispiel #12
0
    async def __call__(self):
        user = get_authenticated_user()
        user_id: str = self.request.matchdict["user"]
        session_id: str = self.request.matchdict["session"]
        if user.id != user_id:
            raise HTTPUnauthorized()

        session_manager = query_utility(ISessionManagerUtility)
        if session_manager is not None:
            value = await session_manager.get_session(user.id, session_id)
            return json.loads(value)
        else:
            raise HTTPNotAcceptable()
Beispiel #13
0
    async def __call__(self):
        user = get_authenticated_user(self.request)
        data = {
            'iat': datetime.utcnow(),
            'exp': datetime.utcnow() + timedelta(seconds=self.token_timeout),
            'id': user.id
        }
        jwt_token = jwt.encode(data,
                               app_settings['jwt']['secret']).decode('utf-8')

        await notify(UserRefreshToken(user, jwt_token))

        return {'exp': data['exp'], 'token': jwt_token}
Beispiel #14
0
 async def __call__(self):
     user = get_authenticated_user()
     serializer = queryMultiAdapter((user, self.request),
                                    IResourceSerializeToJson)
     if serializer:
         data = await serializer()
     else:
         data = {}
     data.update({
         "id": user.id,
         "roles": user.roles,
         "groups": getattr(user, "groups", [])
     })
     return data
Beispiel #15
0
    async def __call__(self):
        user = get_authenticated_user()
        data = {
            "iat": datetime.utcnow(),
            "exp": datetime.utcnow() + timedelta(seconds=self.token_timeout),
            "id": user.id,
        }
        jwt_token = jwt.encode(
            data, app_settings["jwt"]["secret"], algorithm=app_settings["jwt"]["algorithm"]
        ).decode("utf-8")

        await notify(UserRefreshToken(user, jwt_token))

        return {"exp": data["exp"], "token": jwt_token}
Beispiel #16
0
    async def __call__(self):
        user = get_authenticated_user()
        self.policy = get_security_policy(user)
        definition = copy.deepcopy(
            app_settings["swagger"]["base_configuration"])
        vhm = self.request.headers.get("X-VirtualHost-Monster")

        if not app_settings["swagger"].get("base_url"):
            if vhm:
                parsed_url = urlparse(vhm)
                host = parsed_url.netloc
                scheme = parsed_url.scheme
                base_path = parsed_url.path
            else:
                host = self.request.host
                scheme = get_request_scheme(self.request)
                base_path = ""
            url = os.path.join(f"{scheme}://{host}", base_path)
        else:
            url = app_settings["swagger"]["base_url"]

        definition["servers"][0]["url"] = url

        if "version" not in definition["info"]:
            definition["info"]["version"] = pkg_resources.get_distribution(
                "guillotina").version

        api_defs = app_settings["api_definition"]

        path = get_full_content_path(self.context)

        for dotted_iface in api_defs.keys():
            iface = resolve_dotted_name(dotted_iface)
            if iface.providedBy(self.context):
                iface_conf = api_defs[dotted_iface]
                self.get_endpoints(iface_conf, path, definition["paths"])

        definition["components"]["schemas"] = app_settings[
            "json_schema_definitions"]
        return definition
Beispiel #17
0
def serialize_request(request: IRequest) -> SerializedRequest:
    """Serializes request data so that it can be sent to rabbitmq
    """
    req_data = {
        "url": str(request.url),
        "headers": dict(request.headers),
        "method": request.method,
        "annotations": getattr(request, "annotations", {}),
    }
    user = get_authenticated_user()
    if user is not None:
        try:
            req_data["user"] = {
                "id":
                user.id,
                "roles": [
                    name
                    for name, setting in user.roles.items()  # type: ignore
                    if setting == Allow
                ],
                "groups":
                user.groups,
                "headers":
                dict(request.headers),
                "data":
                getattr(user, "data", {}),
            }
        except AttributeError:
            pass

    container = task_vars.container.get()
    if container is not None:
        req_data["container_url"] = IAbsoluteURL(container,
                                                 request)()  # type: ignore

    return cast(SerializedRequest, req_data)
Beispiel #18
0
    async def __call__(self):
        user = get_authenticated_user()

        data = {
            "iat": datetime.utcnow(),
            "exp": datetime.utcnow() + timedelta(seconds=app_settings["jwt"]["token_expiration"]),
            "id": user.id,
        }

        session_manager = query_utility(ISessionManagerUtility)
        if session_manager is not None:
            try:
                session = await session_manager.refresh_session(user.id, user._v_session)
                data["session"] = session
            except AttributeError:
                raise HTTPPreconditionFailed("Session manager configured but no session on jwt")

        jwt_token = jwt.encode(
            data, app_settings["jwt"]["secret"], algorithm=app_settings["jwt"]["algorithm"]
        ).decode("utf-8")

        await notify(UserRefreshToken(user, jwt_token))

        return {"exp": data["exp"], "token": jwt_token}
Beispiel #19
0
def test_get_authenticated_user_without_request(dummy_guillotina):
    login()
    assert utils.get_authenticated_user() is not None
Beispiel #20
0
def test_get_authenticated_user_without_request(dummy_guillotina):
    db = get_db(dummy_guillotina, 'db')
    request = get_mocked_request(db)
    login(request)
    assert utils.get_authenticated_user() is not None
Beispiel #21
0
def get_token(request):
    user = get_authenticated_user(request)
    token = uuid.uuid4().hex
    _tokens[token] = user.id
    return token
Beispiel #22
0
    def __init__(
        self,
        utility,
        context,
        response=noop_response,
        force=False,
        log_details=False,
        memory_tracking=False,
        request=None,
        bulk_size=40,
        full=False,
        reindex_security=False,
        mapping_only=False,
        index_manager=None,
        children_only=False,
        lookup_index=False,
        cache=True,
    ):
        self.utility = utility
        self.context = context
        self.response = response
        self.force = force
        self.full = full
        self.log_details = log_details
        self.memory_tracking = memory_tracking
        self.bulk_size = bulk_size
        self.reindex_security = reindex_security
        self.children_only = children_only
        self.lookup_index = lookup_index
        if mapping_only and full:
            raise Exception("Can not do a full reindex and a mapping only migration")
        self.mapping_only = mapping_only

        self.txn = get_current_transaction()
        if not cache:
            # make sure that we don't cache requests...
            self.txn._cache = DummyCache(self.txn)

        self.request = request
        self.container = get_current_container()
        self.conn = utility.get_connection()

        if index_manager is None:
            self.index_manager = get_adapter(self.container, IIndexManager)
        else:
            self.index_manager = index_manager

        self.user = get_authenticated_user()
        self.policy = get_security_policy(self.user)
        self.indexer = Indexer()

        self.batch = {}
        self.indexed = 0
        self.processed = 0
        self.missing = []
        self.orphaned = []
        self.existing = []
        self.errors = []
        self.mapping_diff = {}
        self.start_time = self.index_start_time = time.time()
        self.reindex_futures = []
        self.status = "started"
        self.active_task_id = None

        self.copied_docs = 0

        self.work_index_name = None
        self.sub_indexes = []
Beispiel #23
0
async def add_task(func,
                   *args,
                   _request=None,
                   _retries=3,
                   _task_id=None,
                   **kwargs):
    """Given a function and its arguments, it adds it as a task to be ran
    by workers.
    """
    # Get the request and prepare request data
    if _request is None:
        _request = get_current_request()

    req_data = {
        'url': str(_request.url),
        'headers': dict(_request.headers),
        'method': _request.method,
        'annotations': getattr(_request, 'annotations', {})
    }
    user = get_authenticated_user()
    if user is not None:
        try:
            req_data['user'] = {
                'id':
                user.id,
                'roles': [
                    name for name, setting in user.roles.items()
                    if setting == Allow
                ],
                'groups':
                user.groups,
                'headers':
                dict(_request.headers),
                'data':
                getattr(user, 'data', {})
            }
        except AttributeError:
            pass

    container = task_vars.container.get()
    if container is not None:
        req_data['container_url'] = IAbsoluteURL(container, _request)()

    if _task_id is None:
        task_id = generate_task_id()
    else:
        task_id = _task_id

    retries = 0
    while True:
        # Get the rabbitmq connection
        channel, transport, protocol = await amqp.get_connection()
        try:
            state = TaskState(task_id)
            dotted_name = get_dotted_name(func)
            db = task_vars.db.get()
            logger.info(f'Scheduling task: {task_id}: {dotted_name}')
            data = json.dumps({
                'func': dotted_name,
                'args': args,
                'kwargs': kwargs,
                'db_id': getattr(db, 'id', None),
                'container_id': getattr(container, 'id', None),
                'req_data': req_data,
                'task_id': task_id
            })
            # Publish task data on rabbitmq
            await channel.publish(
                data,
                exchange_name=app_settings['amqp']['exchange'],
                routing_key=app_settings['amqp']['queue'],
                properties={'delivery_mode': 2})
            # Update tasks's global state
            state_manager = get_state_manager()
            await update_task_scheduled(state_manager,
                                        task_id,
                                        updated=time.time())
            logger.info(f'Scheduled task: {task_id}: {dotted_name}')
            return state
        except (aioamqp.AmqpClosedConnection,
                aioamqp.exceptions.ChannelClosed):
            await amqp.remove_connection()
            if retries >= _retries:
                raise
            retries += 1
Beispiel #24
0
def test_get_authenticated_user_without_request(dummy_guillotina):
    db = get_db(dummy_guillotina, 'db')
    request = get_mocked_request(db)
    login(request)
    assert utils.get_authenticated_user() is not None