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 `read` implies, and loading one in is
|
||||||
/// its own grant rather than something `insert` implies — so a superadmin can
|
/// 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
|
/// 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 EXPORT: &str = "export";
|
||||||
pub(crate) const IMPORT: &str = "import";
|
pub(crate) const IMPORT: &str = "import";
|
||||||
|
|
||||||
@@ -146,6 +147,25 @@ mod tests {
|
|||||||
assert!(!outranks("sales", "clerk"));
|
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]
|
#[test]
|
||||||
fn data_wildcards_match_the_server_object_shapes() {
|
fn data_wildcards_match_the_server_object_shapes() {
|
||||||
let global = snapshot(&[("data:*", "read")]);
|
let global = snapshot(&[("data:*", "read")]);
|
||||||
|
|||||||
@@ -29,16 +29,18 @@ pub(crate) struct Profile {
|
|||||||
/// The tables one transfer page may offer.
|
/// The tables one transfer page may offer.
|
||||||
///
|
///
|
||||||
/// `transfer_action` is the page's own grant — `export` or `import`.
|
/// `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
|
/// `row_action` is a second grant to require, for a page whose work the backend
|
||||||
/// makes, so a table offered on the strength of the transfer grant alone would
|
/// authorizes as ordinary row calls: an export downloads by reading rows, so it
|
||||||
/// be refused halfway through the download. A table appears here only when the
|
/// passes `read` and a table offered on the strength of `export` alone would be
|
||||||
/// role holds both.
|
/// 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(
|
pub(crate) async fn load_catalog(
|
||||||
state: AppState,
|
state: AppState,
|
||||||
headers: &HeaderMap,
|
headers: &HeaderMap,
|
||||||
transfer_action: &str,
|
transfer_action: &str,
|
||||||
row_action: &str,
|
row_action: Option<&str>,
|
||||||
) -> Result<Catalog, LoadError> {
|
) -> Result<Catalog, LoadError> {
|
||||||
let request = authenticated_request(headers, GetAuthorizationRequest {})
|
let request = authenticated_request(headers, GetAuthorizationRequest {})
|
||||||
.map_err(|_| LoadError::Unauthenticated)?;
|
.map_err(|_| LoadError::Unauthenticated)?;
|
||||||
@@ -58,7 +60,9 @@ pub(crate) async fn load_catalog(
|
|||||||
}
|
}
|
||||||
let permits = |profile: &str, table: &str| {
|
let permits = |profile: &str, table: &str| {
|
||||||
crate::authz::permits_table(&authorization, profile, table, transfer_action)
|
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 mut definitions = state.definitions;
|
||||||
let tree = definitions
|
let tree = definitions
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ pub(crate) async fn load_page(
|
|||||||
state: AppState,
|
state: AppState,
|
||||||
headers: &HeaderMap,
|
headers: &HeaderMap,
|
||||||
) -> Result<ExportPageState, LoadError> {
|
) -> 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 {
|
Ok(ExportPageState {
|
||||||
nav: crate::ui::Nav::from_authorization(headers, "", &catalog.authorization),
|
nav: crate::ui::Nav::from_authorization(headers, "", &catalog.authorization),
|
||||||
catalog,
|
catalog,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ pub(crate) async fn load_page(
|
|||||||
form: ImportForm,
|
form: ImportForm,
|
||||||
step: Step,
|
step: Step,
|
||||||
) -> Result<ImportPageState, LoadError> {
|
) -> 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 {
|
Ok(ImportPageState {
|
||||||
nav: crate::ui::Nav::from_authorization(headers, "", &catalog.authorization),
|
nav: crate::ui::Nav::from_authorization(headers, "", &catalog.authorization),
|
||||||
catalog,
|
catalog,
|
||||||
|
|||||||
Reference in New Issue
Block a user