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

Fix OpenApi output for mode follow-privileges #2357

Merged

Conversation

wolfgangwalther
Copy link
Member

This demonstrates a breaking change in the latest pre-release by adding a new test for openapi output of views.

Related to #2356.

@steve-chavez
Copy link
Member

@wolfgangwalther As a workaround, if you use PGRST_OPENAPI_MODE="ignore-privileges" then the PK will be detected.

@steve-chavez
Copy link
Member

On PGRST_OPENAPI_MODE="follow-privileges" the problem is that accessibleTables is a query that runs everytime the OpenAPI endpoint is hit. While on ignore-privileges we use the actual schema cache.

handleOpenApi :: Bool -> Schema -> RequestContext -> DbHandler Wai.Response
handleOpenApi headersOnly tSchema (RequestContext conf@AppConfig{..} dbStructure apiRequest ctxPgVersion) = do
body <-
lift $ case configOpenApiMode of
OAFollowPriv ->
OpenAPI.encode conf dbStructure
<$> SQL.statement [tSchema] (DbStructure.accessibleTables ctxPgVersion configDbPreparedStatements)
<*> SQL.statement tSchema (DbStructure.accessibleProcs ctxPgVersion configDbPreparedStatements)
<*> SQL.statement tSchema (DbStructure.schemaDescription configDbPreparedStatements)
OAIgnorePriv ->
OpenAPI.encode conf dbStructure
(HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) $ DbStructure.dbTables dbStructure)
(HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) $ DbStructure.dbProcs dbStructure)
<$> SQL.statement tSchema (DbStructure.schemaDescription configDbPreparedStatements)

The schema cache is augmented with addViewPrimaryKeys, which doesn't occur for accessibleTables.

queryDbStructure :: [Schema] -> [Schema] -> Bool -> SQL.Transaction DbStructure
queryDbStructure schemas extraSearchPath prepared = do
SQL.sql "set local schema ''" -- This voids the search path. The following queries need this for getting the fully qualified name(schema.name) of every db object
pgVer <- SQL.statement mempty pgVersionStatement
tabs <- SQL.statement schemas $ allTables pgVer prepared
keyDeps <- SQL.statement (schemas, extraSearchPath) $ allViewsKeyDependencies prepared
m2oRels <- SQL.statement mempty $ allM2ORels pgVer prepared
procs <- SQL.statement schemas $ allProcs pgVer prepared
let tabsWViewsPks = addViewPrimaryKeys tabs keyDeps
rels = relsToMap $ addO2MRels $ addM2MRels tabsWViewsPks $ addViewM2ORels keyDeps m2oRels

@steve-chavez
Copy link
Member

steve-chavez commented Jul 5, 2022

Before #2254

Get PKcols inside tables

The above was not done and the PKCols were a separate element in the schema cache and this was used for the OpenAPI output.

The fix would be to add addViewPrimaryKeys to the accessibleTables in App.hs.

Edit: The above can't be done because addViewPrimaryKeys no longer has [ViewKeyDependency] at the App.hs module.


Ideally I think we'd use the schema cache for follow-privileges as well instead of doing a query every time. For this we'd have to cache the privileges of the roles that are members of authenticator(connection role) and then filter the OpenAPI output in Haskell code with the role claim of the JWT. Downside is that our schema cache would have to be reloaded for GRANT/REVOKE as well. For now this is too complicated.

Edit: This could also let us reject unauthorized requests at the postgREST level. There's some value in not touching the db when we know the user isn't able to fulfill the request(similar to #1094).

@steve-chavez
Copy link
Member

steve-chavez commented Jul 9, 2022

Another alternative that seems simpler. On accessibleTables/Procs we don't query all the metadata again but just the list of tables/procs that are accessible by the role, then we filter the tables/procs from the cache with that list in Haskell code.

There would be no caching if we go this way, but that could be added later.

@wolfgangwalther
Copy link
Member Author

@wolfgangwalther As a workaround, if you use PGRST_OPENAPI_MODE="ignore-privileges" then the PK will be detected.

I tried that and it seems like it works... but not quite, yet. It looks like PKs are not detected through multiple views recursively anymore. So one view selects from another view which selects a PK from a table.

Does this make sense? Is this expected, because of changes to embedding? Or should I try to put together a test-case?

@wolfgangwalther
Copy link
Member Author

@wolfgangwalther As a workaround, if you use PGRST_OPENAPI_MODE="ignore-privileges" then the PK will be detected.

I tried that and it seems like it works... but not quite, yet. It looks like PKs are not detected through multiple views recursively anymore. So one view selects from another view which selects a PK from a table.

Does this make sense? Is this expected, because of changes to embedding? Or should I try to put together a test-case?

Hm. The few ones I'm still missing might also be related to multi column PKs. Will have to put a test-case together, eventually, I guess.

@steve-chavez
Copy link
Member

Does this make sense? Is this expected, because of changes to embedding? Or should I try to put together a test-case?

Hm, no. PK detection on views recursively should work. I didn't expect to break that. A test case would be great, yes.

@wolfgangwalther
Copy link
Member Author

Ideally I think we'd use the schema cache for follow-privileges as well instead of doing a query every time. For this we'd have to cache the privileges of the roles that are members of authenticator(connection role) and then filter the OpenAPI output in Haskell code with the role claim of the JWT. Downside is that our schema cache would have to be reloaded for GRANT/REVOKE as well. For now this is too complicated.

What about running a query to only fetch the current privileges each time the openapi output is requested - and then applying those privileges to the schema cache?

@wolfgangwalther wolfgangwalther changed the title test: Add test for openapi output of views Fix OpenApi output for mode follow-privileges Oct 26, 2022
@wolfgangwalther wolfgangwalther marked this pull request as ready for review October 26, 2022 07:45
@wolfgangwalther
Copy link
Member Author

What about running a query to only fetch the current privileges each time the openapi output is requested - and then applying those privileges to the schema cache?

I did it this way for the tables query. Doing the same for accessibleProcs would be a bit more effort, because those are not uniquely identified by schema/name alone.

@steve-chavez WDYT?

This is based on #2526, so that commit shows up here, too.

@steve-chavez
Copy link
Member

Approach looks good! Could you make the change independent of #2526? I still don't understand that one and it might take me more time but 6b5f916 can be merged

This was introduced in d5b92a4. Before
this change, the OpenApi output would have <pk/> annotations for views,
too. After this change, they got lost for mode follow-privileges, because
the pks are refined in haskell code, but the request only fetches all
the tables again, but not the view dependencies.

This fix changes follow-privileges to only fetch a list of accessible
tables, which is then used to filter the tables in the schema cache.

Fixes PostgREST#2356

Signed-off-by: Wolfgang Walther <walther@technowledgy.de>
@wolfgangwalther wolfgangwalther force-pushed the pk-description-views branch 2 times, most recently from c576af8 to 3bee6b1 Compare October 26, 2022 19:31
@wolfgangwalther wolfgangwalther merged commit 3bee6b1 into PostgREST:main Oct 26, 2022
@wolfgangwalther wolfgangwalther deleted the pk-description-views branch October 26, 2022 19:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants