Skip to content

[RFC] Add a system for getting parent resource and play security #7107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
lyrixx opened this issue Apr 22, 2025 · 6 comments
Closed

[RFC] Add a system for getting parent resource and play security #7107

lyrixx opened this issue Apr 22, 2025 · 6 comments

Comments

@lyrixx
Copy link
Contributor

lyrixx commented Apr 22, 2025

Hello,

It's still a bit vague in my mind, But I always face the same issue,
and I did not found a way to code it.

I have a resource name Crawl (stored and Doctrine, but exposed via a custom DTO + security) and some subresource named CrawlUrl (stored in ClickHouse, but exposed via a custom DTO + security)

I have the following endpoint

  • /crawls/{id}
  • /crawls/{crawlId}/crawl-urls/{id}

In my CrawlUrlItemProvider (for examples) I would like to be able to write such code

public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?CrawlUrl
    {
        $crawl = $this->crawlProvider->provide($operation, ['id' => $uriVariables['crawlId']], $context);

        // here, $crawl is either an instance of my CrawlDto, and security has passed,
        // or null in case the object was not found in the DB.

Did I miss something, or is it something out of scope? If no, could this be implemented in APIP?

I imagine something like:

#[ApiResource(
    operations: [
        new Get(
            uriTemplate: '/crawls/{crawlId}/crawl-urls/{id}',
            requirements: [
                'id' => Requirement::UUID,
                'crawlUrlId' => Requirement::UUID,
            ],
            // ⚠⚠⚠⚠ this is probably bullshit, I don't understand the from/to thing ⚠⚠⚠⚠
            uriVariables: [
                'crawlId' => new Link(
                    fromClass: Crawl::class,
                    parameterName: 'id',
                    identifiers: ['id'],
                ),
                'id' => new Link(
                    toClass: CrawlUrl::class,
                ),
            ],
        ),
    ],
)]
class CrawlUrl

may be linked to #7105

@mrossard
Copy link
Contributor

I don't think there's a way to "play" the security defined on another resource, but if $crawl is a member of your CrawlUrl you should be able to populate it with the Link, then reuse the existing voter with something like is_granted("SOME_CONDITION", object.crawl).

@lyrixx
Copy link
Contributor Author

lyrixx commented Apr 23, 2025

It means I should get the crawl url first, then get the crawl (it's another db storage, so it needs another query anyway) and then play security. There is an extra step here. but but, may be I'm overthinking here...

But I have another example, maybe more explicit.
On the endpoint /crawls/{id}/crawl-urls, I must get the crawl before, to play security, and then get all CrawlUrls. I cannot do the opposite

@mrossard
Copy link
Contributor

mrossard commented Apr 23, 2025

But I have another example, maybe more explicit. On the endpoint /crawls/{id}/crawl-urls, I must get the crawl before, to play security, and then get all CrawlUrls. I cannot do the opposite

You can pass the id to your Voter, which means you could have something like this on your operation : security: is_granted('READ_CRAWL', request.get('id')), then a Voter that accepts either an id or a Crawl instance.

...different from what you had in mind, no doubt...but i can see lots of difficulties trying to make this automatic 🤔

@divine
Copy link
Contributor

divine commented Apr 23, 2025

It means I should get the crawl url first, then get the crawl (it's another db storage, so it needs another query anyway) and then play security. There is an extra step here. but but, may be I'm overthinking here...

But I have another example, maybe more explicit. On the endpoint /crawls/{id}/crawl-urls, I must get the crawl before, to play security, and then get all CrawlUrls. I cannot do the opposite

Hello,

Maybe you can use https://api-platform.com/docs/core/extensions/ ? It's just another guard to properly query if your data associated with user id as it works quite good for me.

Also I've slightly modified your code:

#[ApiResource(
    operations: [
        new Get(
            uriTemplate: '/crawls/{crawlId}/crawl-urls/{id}',
            requirements: [
                'id' => Requirement::UUID,
                'crawlUrlId' => Requirement::UUID,
            ],
            // ⚠⚠⚠⚠ this is probably bullshit, I don't understand the from/to thing ⚠⚠⚠⚠
            uriVariables: [
                'crawlId' => new Link(
                    fromClass: Crawl::class,
                    // parameterName: 'id', you don't need this?
                    toProperty: 'crawl', // this should be relation https://api-platform.com/docs/admin/handling-relations/#using-an-autocomplete-input-for-relations
                    identifiers: ['id'], // this is Crawl::class id

                ),
                'id' => new Link(
                    fromClass: CrawlUrl::class, // this should be from class?
                ),
            ],
        ),
    ],
)]
class CrawlUrl

Basically this is works great with relation but if you need more custom logic, then you should probably take a look at this #5732 ?

Thanks!

@lyrixx
Copy link
Contributor Author

lyrixx commented Apr 29, 2025

Thanks for the discussion.

I'm closing it in favor of #7112, which is much much better !

@lyrixx lyrixx closed this as not planned Won't fix, can't repro, duplicate, stale Apr 29, 2025
@soyuka
Copy link
Member

soyuka commented Apr 30, 2025

There's security on links:

final class LinkAccessCheckerProvider implements ProviderInterface

You need to specify:

new Link(securityObjectName: 'object', security: 'is_granted()', fromClass: Crawl::class)

This will call:

https://github.com/api-platform/core/blob/dc3af76a0211d669403fadddef7e30ee642a14e0/src/Symfony/Security/State/LinkAccessCheckerProvider.php#L72C1-L73

soyuka added a commit to soyuka/core that referenced this issue Apr 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants