diff --git a/meilisearch-http/tests/auth/authorization.rs b/meilisearch-http/tests/auth/authorization.rs index 98e0a1a1d..7ea232f0b 100644 --- a/meilisearch-http/tests/auth/authorization.rs +++ b/meilisearch-http/tests/auth/authorization.rs @@ -1,56 +1,61 @@ use crate::common::Server; use chrono::{Duration, Utc}; -use maplit::hashmap; +use maplit::{hashmap, hashset}; use once_cell::sync::Lazy; use serde_json::{json, Value}; use std::collections::{HashMap, HashSet}; -static AUTHORIZATIONS: Lazy> = +static AUTHORIZATIONS: Lazy>> = Lazy::new(|| { hashmap! { - ("POST", "/indexes/products/search") => "search", - ("GET", "/indexes/products/search") => "search", - ("POST", "/indexes/products/documents") => "documents.add", - ("GET", "/indexes/products/documents") => "documents.get", - ("GET", "/indexes/products/documents/0") => "documents.get", - ("DELETE", "/indexes/products/documents/0") => "documents.delete", - ("GET", "/tasks") => "tasks.get", - ("GET", "/indexes/products/tasks") => "tasks.get", - ("GET", "/indexes/products/tasks/0") => "tasks.get", - ("PUT", "/indexes/products/") => "indexes.update", - ("GET", "/indexes/products/") => "indexes.get", - ("DELETE", "/indexes/products/") => "indexes.delete", - ("POST", "/indexes") => "indexes.create", - ("GET", "/indexes") => "indexes.get", - ("GET", "/indexes/products/settings") => "settings.get", - ("GET", "/indexes/products/settings/displayed-attributes") => "settings.get", - ("GET", "/indexes/products/settings/distinct-attribute") => "settings.get", - ("GET", "/indexes/products/settings/filterable-attributes") => "settings.get", - ("GET", "/indexes/products/settings/ranking-rules") => "settings.get", - ("GET", "/indexes/products/settings/searchable-attributes") => "settings.get", - ("GET", "/indexes/products/settings/sortable-attributes") => "settings.get", - ("GET", "/indexes/products/settings/stop-words") => "settings.get", - ("GET", "/indexes/products/settings/synonyms") => "settings.get", - ("DELETE", "/indexes/products/settings") => "settings.update", - ("POST", "/indexes/products/settings") => "settings.update", - ("POST", "/indexes/products/settings/displayed-attributes") => "settings.update", - ("POST", "/indexes/products/settings/distinct-attribute") => "settings.update", - ("POST", "/indexes/products/settings/filterable-attributes") => "settings.update", - ("POST", "/indexes/products/settings/ranking-rules") => "settings.update", - ("POST", "/indexes/products/settings/searchable-attributes") => "settings.update", - ("POST", "/indexes/products/settings/sortable-attributes") => "settings.update", - ("POST", "/indexes/products/settings/stop-words") => "settings.update", - ("POST", "/indexes/products/settings/synonyms") => "settings.update", - ("GET", "/indexes/products/stats") => "stats.get", - ("GET", "/stats") => "stats.get", - ("POST", "/dumps") => "dumps.create", - ("GET", "/dumps/0/status") => "dumps.get", - ("GET", "/version") => "version", + ("POST", "/indexes/products/search") => hashset!{"search", "*"}, + ("GET", "/indexes/products/search") => hashset!{"search", "*"}, + ("POST", "/indexes/products/documents") => hashset!{"documents.add", "*"}, + ("GET", "/indexes/products/documents") => hashset!{"documents.get", "*"}, + ("GET", "/indexes/products/documents/0") => hashset!{"documents.get", "*"}, + ("DELETE", "/indexes/products/documents/0") => hashset!{"documents.delete", "*"}, + ("GET", "/tasks") => hashset!{"tasks.get", "*"}, + ("GET", "/indexes/products/tasks") => hashset!{"tasks.get", "*"}, + ("GET", "/indexes/products/tasks/0") => hashset!{"tasks.get", "*"}, + ("PUT", "/indexes/products/") => hashset!{"indexes.update", "*"}, + ("GET", "/indexes/products/") => hashset!{"indexes.get", "*"}, + ("DELETE", "/indexes/products/") => hashset!{"indexes.delete", "*"}, + ("POST", "/indexes") => hashset!{"indexes.create", "*"}, + ("GET", "/indexes") => hashset!{"indexes.get", "*"}, + ("GET", "/indexes/products/settings") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/displayed-attributes") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/distinct-attribute") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/filterable-attributes") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/ranking-rules") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/searchable-attributes") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/sortable-attributes") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/stop-words") => hashset!{"settings.get", "*"}, + ("GET", "/indexes/products/settings/synonyms") => hashset!{"settings.get", "*"}, + ("DELETE", "/indexes/products/settings") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/displayed-attributes") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/distinct-attribute") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/filterable-attributes") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/ranking-rules") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/searchable-attributes") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/sortable-attributes") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/stop-words") => hashset!{"settings.update", "*"}, + ("POST", "/indexes/products/settings/synonyms") => hashset!{"settings.update", "*"}, + ("GET", "/indexes/products/stats") => hashset!{"stats.get", "*"}, + ("GET", "/stats") => hashset!{"stats.get", "*"}, + ("POST", "/dumps") => hashset!{"dumps.create", "*"}, + ("GET", "/dumps/0/status") => hashset!{"dumps.get", "*"}, + ("GET", "/version") => hashset!{"version", "*"}, } }); -static ALL_ACTIONS: Lazy> = - Lazy::new(|| AUTHORIZATIONS.values().cloned().collect()); +static ALL_ACTIONS: Lazy> = Lazy::new(|| { + AUTHORIZATIONS + .values() + .cloned() + .reduce(|l, r| l.union(&r).cloned().collect()) + .unwrap() +}); static INVALID_RESPONSE: Lazy = Lazy::new(|| { json!({"message": "The provided API key is invalid.", @@ -147,7 +152,7 @@ async fn error_access_unauthorized_action() { // Patch API key letting all rights but the needed one. let content = json!({ - "actions": ALL_ACTIONS.iter().cloned().filter(|a| a != action).collect::>(), + "actions": ALL_ACTIONS.difference(action).collect::>(), }); let (_, code) = server.patch_api_key(&key, content).await; assert_eq!(code, 200); @@ -179,36 +184,23 @@ async fn access_authorized_restricted_index() { let key = response["key"].as_str().unwrap(); server.use_api_key(&key); - for ((method, route), action) in AUTHORIZATIONS.iter() { - // Patch API key letting only the needed action. - let content = json!({ - "actions": [action], - }); + for ((method, route), actions) in AUTHORIZATIONS.iter() { + for action in actions { + // Patch API key letting only the needed action. + let content = json!({ + "actions": [action], + }); - server.use_api_key("MASTER_KEY"); - let (_, code) = server.patch_api_key(&key, content).await; - assert_eq!(code, 200); + server.use_api_key("MASTER_KEY"); + let (_, code) = server.patch_api_key(&key, content).await; + assert_eq!(code, 200); - server.use_api_key(&key); - let (response, code) = server.dummy_request(method, route).await; + server.use_api_key(&key); + let (response, code) = server.dummy_request(method, route).await; - assert_ne!(response, INVALID_RESPONSE.clone()); - assert_ne!(code, 403); - - // Patch API key using action all action. - let content = json!({ - "actions": ["*"], - }); - - server.use_api_key("MASTER_KEY"); - let (_, code) = server.patch_api_key(&key, content).await; - assert_eq!(code, 200); - - server.use_api_key(&key); - let (response, code) = server.dummy_request(method, route).await; - - assert_ne!(response, INVALID_RESPONSE.clone()); - assert_ne!(code, 403); + assert_ne!(response, INVALID_RESPONSE.clone()); + assert_ne!(code, 403); + } } } @@ -231,36 +223,23 @@ async fn access_authorized_no_index_restriction() { let key = response["key"].as_str().unwrap(); server.use_api_key(&key); - for ((method, route), action) in AUTHORIZATIONS.iter() { - server.use_api_key("MASTER_KEY"); + for ((method, route), actions) in AUTHORIZATIONS.iter() { + for action in actions { + server.use_api_key("MASTER_KEY"); - // Patch API key letting only the needed action. - let content = json!({ - "actions": [action], - }); - let (_, code) = server.patch_api_key(&key, content).await; - assert_eq!(code, 200); + // Patch API key letting only the needed action. + let content = json!({ + "actions": [action], + }); + let (_, code) = server.patch_api_key(&key, content).await; + assert_eq!(code, 200); - server.use_api_key(&key); - let (response, code) = server.dummy_request(method, route).await; + server.use_api_key(&key); + let (response, code) = server.dummy_request(method, route).await; - assert_ne!(response, INVALID_RESPONSE.clone()); - assert_ne!(code, 403); - - // Patch API key using action all action. - let content = json!({ - "actions": ["*"], - }); - - server.use_api_key("MASTER_KEY"); - let (_, code) = server.patch_api_key(&key, content).await; - assert_eq!(code, 200); - - server.use_api_key(&key); - let (response, code) = server.dummy_request(method, route).await; - - assert_ne!(response, INVALID_RESPONSE.clone()); - assert_ne!(code, 403); + assert_ne!(response, INVALID_RESPONSE.clone()); + assert_ne!(code, 403); + } } } @@ -514,7 +493,8 @@ async fn error_creating_index_without_action() { // create key with access on all indexes. let content = json!({ "indexes": ["*"], - "actions": ALL_ACTIONS.iter().cloned().filter(|a| *a != "indexes.create").collect::>(), + // Give all action but the ones allowing to create an index. + "actions": ALL_ACTIONS.iter().cloned().filter(|a| !AUTHORIZATIONS.get(&("POST","/indexes")).unwrap().contains(a)).collect::>(), "expiresAt": "2050-11-13T00:00:00Z" }); let (response, code) = server.add_api_key(content).await;