read table definition if I can import - web allows for import export to authorized users
This commit is contained in:
2
server
2
server
Submodule server updated: b7504c894c...645b45e81b
@@ -19,7 +19,8 @@ pub(crate) const ALL_ECB: &str = "ecb:*";
|
||||
/// its own grant rather than something `read` implies, and loading one in is
|
||||
/// its own grant rather than something `insert` implies — so a superadmin can
|
||||
/// hand a role the row access without the bulk transfer, or the other way
|
||||
/// round.
|
||||
/// round. `import` is the whole authorization for the bulk endpoint: a role
|
||||
/// that holds it may load a file without holding `insert`.
|
||||
pub(crate) const EXPORT: &str = "export";
|
||||
pub(crate) const IMPORT: &str = "import";
|
||||
|
||||
@@ -146,6 +147,25 @@ mod tests {
|
||||
assert!(!outranks("sales", "clerk"));
|
||||
}
|
||||
|
||||
/// The transfer links are shown on the grant and nothing else. A role
|
||||
/// invented this morning holds them exactly as superadmin does, and a role
|
||||
/// with every structural area but no transfer grant sees neither link.
|
||||
#[test]
|
||||
fn the_transfer_links_follow_the_grant_not_the_role_name() {
|
||||
let warehouse = AuthorizationSnapshot {
|
||||
role: "warehouse-night-shift".to_string(),
|
||||
..snapshot(&[("data:acme/stock", IMPORT)])
|
||||
};
|
||||
assert!(can_transfer_anything(&warehouse, IMPORT));
|
||||
assert!(!can_transfer_anything(&warehouse, EXPORT));
|
||||
assert!(permits_table(&warehouse, "acme", "stock", IMPORT));
|
||||
assert!(!permits_table(&warehouse, "acme", "invoice", IMPORT));
|
||||
|
||||
let structural = snapshot(&[(STRUCT_TABLE, MANAGE), (STRUCT_ROLE, MANAGE)]);
|
||||
assert!(!can_transfer_anything(&structural, IMPORT));
|
||||
assert!(!can_transfer_anything(&structural, EXPORT));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn data_wildcards_match_the_server_object_shapes() {
|
||||
let global = snapshot(&[("data:*", "read")]);
|
||||
|
||||
@@ -29,16 +29,18 @@ pub(crate) struct Profile {
|
||||
/// The tables one transfer page may offer.
|
||||
///
|
||||
/// `transfer_action` is the page's own grant — `export` or `import`.
|
||||
/// `row_action` is what the transfer does underneath, `read` or `insert`, and
|
||||
/// it is checked as well: the backend authorizes the row calls the transfer
|
||||
/// makes, so a table offered on the strength of the transfer grant alone would
|
||||
/// be refused halfway through the download. A table appears here only when the
|
||||
/// role holds both.
|
||||
///
|
||||
/// `row_action` is a second grant to require, for a page whose work the backend
|
||||
/// authorizes as ordinary row calls: an export downloads by reading rows, so it
|
||||
/// passes `read` and a table offered on the strength of `export` alone would be
|
||||
/// refused halfway through the download. An import passes `None` — the bulk
|
||||
/// endpoint authorizes `import` itself and never asks for `insert`, so
|
||||
/// requiring one here would hide tables the server would happily accept.
|
||||
pub(crate) async fn load_catalog(
|
||||
state: AppState,
|
||||
headers: &HeaderMap,
|
||||
transfer_action: &str,
|
||||
row_action: &str,
|
||||
row_action: Option<&str>,
|
||||
) -> Result<Catalog, LoadError> {
|
||||
let request = authenticated_request(headers, GetAuthorizationRequest {})
|
||||
.map_err(|_| LoadError::Unauthenticated)?;
|
||||
@@ -58,7 +60,9 @@ pub(crate) async fn load_catalog(
|
||||
}
|
||||
let permits = |profile: &str, table: &str| {
|
||||
crate::authz::permits_table(&authorization, profile, table, transfer_action)
|
||||
&& crate::authz::permits_table(&authorization, profile, table, row_action)
|
||||
&& row_action.is_none_or(|action| {
|
||||
crate::authz::permits_table(&authorization, profile, table, action)
|
||||
})
|
||||
};
|
||||
let mut definitions = state.definitions;
|
||||
let tree = definitions
|
||||
|
||||
@@ -8,7 +8,7 @@ pub(crate) async fn load_page(
|
||||
state: AppState,
|
||||
headers: &HeaderMap,
|
||||
) -> Result<ExportPageState, LoadError> {
|
||||
let catalog = load_catalog(state, headers, crate::authz::EXPORT, "read").await?;
|
||||
let catalog = load_catalog(state, headers, crate::authz::EXPORT, Some("read")).await?;
|
||||
Ok(ExportPageState {
|
||||
nav: crate::ui::Nav::from_authorization(headers, "", &catalog.authorization),
|
||||
catalog,
|
||||
|
||||
@@ -13,7 +13,7 @@ pub(crate) async fn load_page(
|
||||
form: ImportForm,
|
||||
step: Step,
|
||||
) -> Result<ImportPageState, LoadError> {
|
||||
let catalog = load_catalog(state, headers, crate::authz::IMPORT, "insert").await?;
|
||||
let catalog = load_catalog(state, headers, crate::authz::IMPORT, None).await?;
|
||||
Ok(ImportPageState {
|
||||
nav: crate::ui::Nav::from_authorization(headers, "", &catalog.authorization),
|
||||
catalog,
|
||||
|
||||
Reference in New Issue
Block a user