Skip to content
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

Can't retrieve OAS spec for public user #6084

Closed
doodlemania2 opened this issue Jun 4, 2021 · 22 comments · Fixed by #20386
Closed

Can't retrieve OAS spec for public user #6084

doodlemania2 opened this issue Jun 4, 2021 · 22 comments · Fixed by #20386
Assignees
Labels

Comments

@doodlemania2
Copy link

Attempting to generate OAS at /server/specs/oas

Error returns with Access Denied.

GET to /server/specs/graphql work however (same Authorization Token)

Thought it might just be swallowing a deeper error so checked the raw logs and it does indeed show a 403

@miccoh1994

This comment has been minimized.

@rijkvanzanten rijkvanzanten changed the title OAS Broken in .68+? Can't retrieve OAS spec for public user Jun 9, 2021
@MoltenCoffee
Copy link
Contributor

From what I've gathered, this error originates from the following method call:

const meta = (await collectionItemsService.readByQuery({
filter: { collection: { _in: tablesToFetchInfoFor } },
limit: -1,
})) as CollectionMeta[];

with then breaks here:

ast = await authorizationService.processAST(ast, opts?.permissionsAction);

as this throws a ForbiddenException if you don't have all permissions.

@doodlemania2
Copy link
Author

Hrm - being able to generate the OAS would seem to be best suited for an unauthenticated call?

@rijkvanzanten
Copy link
Member

It's supposed to work for either 👍🏻 Just like the graphql one 🙂

The output should be based on the permissions of your current user, regardless of if it's public or not

@doodlemania2
Copy link
Author

nice - in this instance, as an unauthenticated caller, it will fail then by design?

@MoltenCoffee
Copy link
Contributor

The output should be based on the permissions of your current user, regardless of if it's public or not

So if I understand correctly, the output should change based on your current permissions, right?

In that case, the tablesToFetchInfoFor should be generated differently, as currently it's generated by retrieving the names of all available (as in available to Directus) tables.

@rijkvanzanten
Copy link
Member

Nope! Should still work. I see "unauthenticated" as the "public user" 🙂

@MoltenCoffee
Copy link
Contributor

In that case, the tablesToFetchInfoFor should be generated differently, as currently it's generated by retrieving the names of all available (as in available to Directus) tables.

Nevermind, I am in the wrong here, this is exactly what is currently done here. Strange that it doesn't work though..

@rijkvanzanten
Copy link
Member

I believe it's the fact that the specs service is initialized with the accountability info:

const service = new SpecificationService({
accountability: req.accountability,
schema: req.schema,
});

Which makes a call to methods of these fail:

this.fieldsService = new FieldsService(options);
this.collectionsService = new CollectionsService(options);
this.relationsService = new RelationsService(options);

We should take a peak at the graphql one and lift the logic from that (extract it into a shared util)

@MoltenCoffee
Copy link
Contributor

I believe both the GraphQL one and the OAS use the same accountability info. The difference seems to be that the GraphQL information is based on the schema, whereas the OAS information is generated with queries.

The immediate cause of the failure for me seems to be how processAST() operates on the data it receives:

When processAST() receives the ast, this gets transformed into:

const collectionsRequested = getCollectionsFromAST(ast);
// [ { collection: 'directus_collections', field: null } ]

However, it then tries filter the users permissions based on this information:

const permissionsForCollections = uniqWith(
this.schema.permissions.filter((permission) => {
return (
permission.action === action &&
collectionsRequested.map(({ collection }) => collection).includes(permission.collection)
);
}),
(curr, prev) => curr.collection === prev.collection && curr.action === prev.action && curr.role === prev.role
);

However, the this.schema.permissions array does not contain an object where collection is directus_collections, as the public role doesn't have access to that table. If we give the public role read access to this collection, the same issue comes up for directus_fields and directus_relations.

If we give access to these three tables, the user is able to access the OAS data, but I believe they're then able to see everything.

@Nitwel
Copy link
Member

Nitwel commented Aug 23, 2021

The pubic role needs access to directus_collections, directus_fields and directus_relations in order to generate the oas spec.
If not, it returns a 403 Forbidden which makes sense to me. (Rijk already kinda pointed this out)

@MoltenCoffee
Copy link
Contributor

The pubic role needs access to directus_collections, directus_fields and directus_relations in order to generate the oas spec.

I think the primary concern here is that it's inconsistent, as a similar endpoint for GraphQL does work.

@rijkvanzanten
Copy link
Member

@Nitwel That's the problem 🙂

Like @MoltenCoffee mentioned, the oas endpoint should work the same as the graphql endpoint

@mklueh
Copy link

mklueh commented Dec 22, 2021

Shouldn't this be at least part of the documentation?
The first thing I want to see as a new user, after configuring my collection is "what are my endpoints?".
Instead, I have no clue what is going on and I have to google around, till I find this thread here.

@terion-name
Copy link

Like @MoltenCoffee mentioned, the oas endpoint should work the same as the graphql endpoint

@rijkvanzanten but it doesn't. still, now. server/specs/graphql works, server/specs/oas — doesn't

@rijkvanzanten
Copy link
Member

Yup! That's why this is an open issue 👍🏻 It should work the same, but currently doesn't

@johannesschobel
Copy link

Dear @rijkvanzanten , and Directus Team,

first of all, i would like to thank you for this awesome platform. It was a real joy for me to try Directus and work my way through the docs and how everything works.

I recently stumbled upon this issue, and i think this should be handled in a proper way.
Let me quickly explain, what i am trying to do:
I have an existing data model that was created within the directus platform. Currently, i am developing a mobile application with Ionic.
As i would like to have proper typings (i.e., i am developing with TypeScript), i would like to use the OpenAPI Specs that are automatically generated by directus.

I would like to have my development workflow as follows:

  • add / adapt / update the data model in directus
  • run a cli command locally to get the OAS and convert them to proper typescript types
  • use the directus js sdk with these typings

When fiddling around, i noticed a few things that feel somehow strange when working with the latter.

Consider my scenario described above.
In order to see "everything" (i.e., all items resources), i would need to create a dedicated new role that has permission to everything and create a new user, log in via the API, get the OAS and use this to generate my types. Which seems a bit overkill, considering the fact that this works "out of the box" for the graphql schema.

Would it be possible to make the /server/specs/oas route available for public by default and output all routes with all data (request / response models, operations, ...) independent from the actual role and permission of the current user?

In order to call a specific route (i.e., create a new user, update an article item, delete a role, ...) the user still has to have a proper role with the correct permission. The fact that someone may have the information that a specific endpoint exists does not allow to call respective endpoint.

What do you think about this proposal?
All the best and thanks for your time

@rijkvanzanten
Copy link
Member

Linear: ENG-295

@johannesschobel
Copy link

i am sorry, but i cannot login and get the details from linear. can you share this here please?

@rijkvanzanten
Copy link
Member

i am sorry, but i cannot login and get the details from linear. can you share this here please?

It's just a private mirror of the public issue I use for private notes and reminders 🙂

@johannesschobel
Copy link

as @Nitwel mentioned above, the current user accessing the GET /server/specs/oas route, needs access to the following permissions:

  • READ directus_collections
  • READ directus_fields
  • READ directus_relations

This will, however, only show the basic routes, like everything related to authentication or available collections and so on. This does not include information with respect to the custom collections that are available. These are also not shown in the OAS document.

In order to make them available, the user accessing the endpoint furthermore needs permissions for these custom collections, i.e.,

  • READ authors
  • READ articles

Finally, granting READ permissions, however, will only show the GET /items/authors and GET /items/authors/ID routes, but not routes for CREATING (i.e., POST /items/authors), DELETING, UPDATING a respective item / collection. To do so, you would need to grant the public role full access to your models - which you may not want for obvious reasons.

I think, the OAS document should be accessible withouth restrictions (i.e., based on the users permission accessing the document) - the same should apply for the graphql schema file.

Just wanted to make the issue with the additional permissions for resources clear.
All the best,
Johannes

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
Archived in project
Development

Successfully merging a pull request may close this issue.

9 participants