mirror of
https://github.com/meilisearch/MeiliSearch
synced 2024-11-26 06:44:27 +01:00
introduce as many custom error message as possible
This commit is contained in:
parent
a74fb87d1e
commit
7da21bb601
@ -188,6 +188,12 @@ impl AuthFilter {
|
|||||||
self.allow_index_creation && self.is_index_authorized(index)
|
self.allow_index_creation && self.is_index_authorized(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
/// Return true if a tenant token was used to generate the search rules.
|
||||||
|
pub fn is_tenant_token(&self) -> bool {
|
||||||
|
self.search_rules.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_allowed_indexes(allowed_indexes: HashSet<IndexUidPattern>) -> Self {
|
pub fn with_allowed_indexes(allowed_indexes: HashSet<IndexUidPattern>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
search_rules: None,
|
search_rules: None,
|
||||||
@ -205,6 +211,7 @@ impl AuthFilter {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the index is authorized by the API key and the tenant token.
|
||||||
pub fn is_index_authorized(&self, index: &str) -> bool {
|
pub fn is_index_authorized(&self, index: &str) -> bool {
|
||||||
self.key_authorized_indexes.is_index_authorized(index)
|
self.key_authorized_indexes.is_index_authorized(index)
|
||||||
&& self
|
&& self
|
||||||
@ -214,6 +221,44 @@ impl AuthFilter {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Only check if the index is authorized by the API key
|
||||||
|
pub fn api_key_is_index_authorized(&self, index: &str) -> bool {
|
||||||
|
self.key_authorized_indexes.is_index_authorized(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Only check if the index is authorized by the tenant token
|
||||||
|
pub fn tenant_token_is_index_authorized(&self, index: &str) -> bool {
|
||||||
|
self.search_rules
|
||||||
|
.as_ref()
|
||||||
|
.map(|search_rules| search_rules.is_index_authorized(index))
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the list of authorized indexes by the tenant token if any
|
||||||
|
pub fn tenant_token_list_index_authorized(&self) -> Vec<String> {
|
||||||
|
match self.search_rules {
|
||||||
|
Some(ref search_rules) => {
|
||||||
|
let mut indexes: Vec<_> = match search_rules {
|
||||||
|
SearchRules::Set(set) => set.iter().map(|s| s.to_string()).collect(),
|
||||||
|
SearchRules::Map(map) => map.keys().map(|s| s.to_string()).collect(),
|
||||||
|
};
|
||||||
|
indexes.sort_unstable();
|
||||||
|
indexes
|
||||||
|
}
|
||||||
|
None => Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the list of authorized indexes by the api key if any
|
||||||
|
pub fn api_key_list_index_authorized(&self) -> Vec<String> {
|
||||||
|
let mut indexes: Vec<_> = match self.key_authorized_indexes {
|
||||||
|
SearchRules::Set(ref set) => set.iter().map(|s| s.to_string()).collect(),
|
||||||
|
SearchRules::Map(ref map) => map.keys().map(|s| s.to_string()).collect(),
|
||||||
|
};
|
||||||
|
indexes.sort_unstable();
|
||||||
|
indexes
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_index_search_rules(&self, index: &str) -> Option<IndexSearchRules> {
|
pub fn get_index_search_rules(&self, index: &str) -> Option<IndexSearchRules> {
|
||||||
if !self.is_index_authorized(index) {
|
if !self.is_index_authorized(index) {
|
||||||
return None;
|
return None;
|
||||||
|
@ -136,6 +136,7 @@ pub mod policies {
|
|||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
||||||
use meilisearch_auth::{AuthController, AuthFilter, SearchRules};
|
use meilisearch_auth::{AuthController, AuthFilter, SearchRules};
|
||||||
|
use meilisearch_types::error::{Code, ErrorCode};
|
||||||
// reexport actions in policies in order to be used in routes configuration.
|
// reexport actions in policies in order to be used in routes configuration.
|
||||||
pub use meilisearch_types::keys::{actions, Action};
|
pub use meilisearch_types::keys::{actions, Action};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -151,14 +152,26 @@ pub mod policies {
|
|||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum AuthError {
|
pub enum AuthError {
|
||||||
#[error("Tenant token expired. Was valid up to `{exp}` and we're now `{now}`")]
|
#[error("Tenant token expired. Was valid up to `{exp}` and we're now `{now}`.")]
|
||||||
ExpiredTenantToken { exp: i64, now: i64 },
|
ExpiredTenantToken { exp: i64, now: i64 },
|
||||||
#[error("The provided API key is invalid.")]
|
#[error("The provided API key is invalid.")]
|
||||||
InvalidApiKey,
|
InvalidApiKey,
|
||||||
|
#[error("The provided tenant token cannot acces the index `{index}`, allowed indexes are {allowed:?}.")]
|
||||||
|
TenantTokenAccessingnUnauthorizedIndex { index: String, allowed: Vec<String> },
|
||||||
|
#[error(
|
||||||
|
"The API key used to generate this tenant token cannot acces the index `{index}`."
|
||||||
|
)]
|
||||||
|
TenantTokenApiKeyAccessingnUnauthorizedIndex { index: String },
|
||||||
|
#[error(
|
||||||
|
"The API key cannot acces the index `{index}`, authorized indexes are {allowed:?}."
|
||||||
|
)]
|
||||||
|
ApiKeyAccessingnUnauthorizedIndex { index: String, allowed: Vec<String> },
|
||||||
#[error("The provided tenant token is invalid.")]
|
#[error("The provided tenant token is invalid.")]
|
||||||
InvalidTenantToken,
|
InvalidTenantToken,
|
||||||
#[error("Could not decode tenant token, {0}")]
|
#[error("Could not decode tenant token, {0}.")]
|
||||||
CouldNotDecodeTenantToken(jsonwebtoken::errors::Error),
|
CouldNotDecodeTenantToken(jsonwebtoken::errors::Error),
|
||||||
|
#[error("Invalid action `{0}`.")]
|
||||||
|
InternalInvalidAction(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<jsonwebtoken::errors::Error> for AuthError {
|
impl From<jsonwebtoken::errors::Error> for AuthError {
|
||||||
@ -172,6 +185,15 @@ pub mod policies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ErrorCode for AuthError {
|
||||||
|
fn error_code(&self) -> Code {
|
||||||
|
match self {
|
||||||
|
AuthError::InternalInvalidAction(_) => Code::Internal,
|
||||||
|
_ => Code::InvalidApiKey,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn tenant_token_validation() -> Validation {
|
fn tenant_token_validation() -> Validation {
|
||||||
let mut validation = Validation::default();
|
let mut validation = Validation::default();
|
||||||
validation.validate_exp = false;
|
validation.validate_exp = false;
|
||||||
@ -233,13 +255,37 @@ pub mod policies {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// check that the indexes are allowed
|
// check that the indexes are allowed
|
||||||
let action = Action::from_repr(A).ok_or(AuthError::InvalidTenantToken)?;
|
let action = Action::from_repr(A).ok_or(AuthError::InternalInvalidAction(A))?;
|
||||||
let auth_filter = auth
|
let auth_filter = auth
|
||||||
.get_key_filters(key_uuid, search_rules)
|
.get_key_filters(key_uuid, search_rules)
|
||||||
.map_err(|_e| AuthError::InvalidTenantToken)?;
|
.map_err(|_e| AuthError::InvalidApiKey)?;
|
||||||
if auth.is_key_authorized(key_uuid, action, index).unwrap_or(false)
|
|
||||||
&& index.map(|index| auth_filter.is_index_authorized(index)).unwrap_or(true)
|
// First check if the index is authorized in the tenant token, this is a public
|
||||||
{
|
// information, we can return a nice error message.
|
||||||
|
if let Some(index) = index {
|
||||||
|
if !auth_filter.tenant_token_is_index_authorized(index) {
|
||||||
|
return Err(AuthError::TenantTokenAccessingnUnauthorizedIndex {
|
||||||
|
index: index.to_string(),
|
||||||
|
allowed: auth_filter.tenant_token_list_index_authorized(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !auth_filter.api_key_is_index_authorized(index) {
|
||||||
|
if auth_filter.is_tenant_token() {
|
||||||
|
// If the error comes from a tenant token we cannot share the list
|
||||||
|
// of authorized indexes in the API key. This is not public information.
|
||||||
|
return Err(AuthError::TenantTokenApiKeyAccessingnUnauthorizedIndex {
|
||||||
|
index: index.to_string(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Otherwise we can share the
|
||||||
|
return Err(AuthError::ApiKeyAccessingnUnauthorizedIndex {
|
||||||
|
index: index.to_string(),
|
||||||
|
allowed: auth_filter.api_key_list_index_authorized(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if auth.is_key_authorized(key_uuid, action, index).unwrap_or(false) {
|
||||||
return Ok(auth_filter);
|
return Ok(auth_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +309,6 @@ pub mod policies {
|
|||||||
let key = if let Some(key) = auth.generate_key(uid) {
|
let key = if let Some(key) = auth.generate_key(uid) {
|
||||||
key
|
key
|
||||||
} else {
|
} else {
|
||||||
/// Only happens when no master key has been set
|
|
||||||
return Err(AuthError::InvalidTenantToken);
|
return Err(AuthError::InvalidTenantToken);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ pub static ALL_ACTIONS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
|||||||
});
|
});
|
||||||
|
|
||||||
static INVALID_RESPONSE: Lazy<Value> = Lazy::new(|| {
|
static INVALID_RESPONSE: Lazy<Value> = Lazy::new(|| {
|
||||||
json!({"message": "The provided API key is invalid.",
|
json!({"message": null,
|
||||||
"code": "invalid_api_key",
|
"code": "invalid_api_key",
|
||||||
"type": "auth",
|
"type": "auth",
|
||||||
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
@ -119,7 +119,8 @@ async fn error_access_expired_key() {
|
|||||||
thread::sleep(time::Duration::new(1, 0));
|
thread::sleep(time::Duration::new(1, 0));
|
||||||
|
|
||||||
for (method, route) in AUTHORIZATIONS.keys() {
|
for (method, route) in AUTHORIZATIONS.keys() {
|
||||||
let (response, code) = server.dummy_request(method, route).await;
|
let (mut response, code) = server.dummy_request(method, route).await;
|
||||||
|
response["message"] = serde_json::json!(null);
|
||||||
|
|
||||||
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?}", method, route);
|
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?}", method, route);
|
||||||
assert_eq!(403, code, "{:?}", &response);
|
assert_eq!(403, code, "{:?}", &response);
|
||||||
@ -149,7 +150,8 @@ async fn error_access_unauthorized_index() {
|
|||||||
// filter `products` index routes
|
// filter `products` index routes
|
||||||
.filter(|(_, route)| route.starts_with("/indexes/products"))
|
.filter(|(_, route)| route.starts_with("/indexes/products"))
|
||||||
{
|
{
|
||||||
let (response, code) = server.dummy_request(method, route).await;
|
let (mut response, code) = server.dummy_request(method, route).await;
|
||||||
|
response["message"] = serde_json::json!(null);
|
||||||
|
|
||||||
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?}", method, route);
|
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?}", method, route);
|
||||||
assert_eq!(403, code, "{:?}", &response);
|
assert_eq!(403, code, "{:?}", &response);
|
||||||
@ -176,7 +178,8 @@ async fn error_access_unauthorized_action() {
|
|||||||
|
|
||||||
let key = response["key"].as_str().unwrap();
|
let key = response["key"].as_str().unwrap();
|
||||||
server.use_api_key(key);
|
server.use_api_key(key);
|
||||||
let (response, code) = server.dummy_request(method, route).await;
|
let (mut response, code) = server.dummy_request(method, route).await;
|
||||||
|
response["message"] = serde_json::json!(null);
|
||||||
|
|
||||||
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?}", method, route);
|
assert_eq!(response, INVALID_RESPONSE.clone(), "on route: {:?} - {:?}", method, route);
|
||||||
assert_eq!(403, code, "{:?}", &response);
|
assert_eq!(403, code, "{:?}", &response);
|
||||||
|
@ -478,6 +478,21 @@ async fn invalid_auth_format() {
|
|||||||
}
|
}
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
|
let req = test::TestRequest::get().uri("/indexes/dog/documents").to_request();
|
||||||
|
let res = test::call_service(&app, req).await;
|
||||||
|
let status_code = res.status();
|
||||||
|
let body = test::read_body(res).await;
|
||||||
|
let response: Value = serde_json::from_slice(&body).unwrap_or_default();
|
||||||
|
snapshot!(status_code, @"401 Unauthorized");
|
||||||
|
snapshot!(response, @r###"
|
||||||
|
{
|
||||||
|
"message": "The Authorization header is missing. It must use the bearer authorization method.",
|
||||||
|
"code": "missing_authorization_header",
|
||||||
|
"type": "auth",
|
||||||
|
"link": "https://docs.meilisearch.com/errors#missing_authorization_header"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
|
||||||
let (response, status_code) =
|
let (response, status_code) =
|
||||||
send_request_with_custom_auth(&app, "/indexes/dog/documents", "Bearer").await;
|
send_request_with_custom_auth(&app, "/indexes/dog/documents", "Bearer").await;
|
||||||
snapshot!(status_code, @"403 Forbidden");
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
@ -489,9 +504,15 @@ async fn invalid_auth_format() {
|
|||||||
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
}
|
}
|
||||||
"###);
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn invalid_api_key() {
|
||||||
|
let server = Server::new_auth().await;
|
||||||
|
let app = server.init_web_app().await;
|
||||||
|
|
||||||
let (response, status_code) =
|
let (response, status_code) =
|
||||||
send_request_with_custom_auth(&app, "/indexes/dog/documents", "Bearer kefir").await;
|
send_request_with_custom_auth(&app, "/indexes/dog/search", "Bearer kefir").await;
|
||||||
snapshot!(status_code, @"403 Forbidden");
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
snapshot!(response, @r###"
|
snapshot!(response, @r###"
|
||||||
{
|
{
|
||||||
@ -502,6 +523,54 @@ async fn invalid_auth_format() {
|
|||||||
}
|
}
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
|
let uuid = Uuid::nil();
|
||||||
|
let key = json!({ "actions": ["search"], "indexes": ["dog"], "expiresAt": null, "uid": uuid.to_string() });
|
||||||
|
let req = test::TestRequest::post()
|
||||||
|
.uri("/keys")
|
||||||
|
.insert_header(("Authorization", "Bearer MASTER_KEY"))
|
||||||
|
.set_json(&key)
|
||||||
|
.to_request();
|
||||||
|
let res = test::call_service(&app, req).await;
|
||||||
|
let body = test::read_body(res).await;
|
||||||
|
let response: Value = serde_json::from_slice(&body).unwrap_or_default();
|
||||||
|
snapshot!(json_string!(response, { ".createdAt" => "[date]", ".updatedAt" => "[date]" }), @r###"
|
||||||
|
{
|
||||||
|
"name": null,
|
||||||
|
"description": null,
|
||||||
|
"key": "aeb94973e0b6e912d94165430bbe87dee91a7c4f891ce19050c3910ec96977e9",
|
||||||
|
"uid": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"actions": [
|
||||||
|
"search"
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
"dog"
|
||||||
|
],
|
||||||
|
"expiresAt": null,
|
||||||
|
"createdAt": "[date]",
|
||||||
|
"updatedAt": "[date]"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
let key = response["key"].as_str().unwrap();
|
||||||
|
|
||||||
|
let (response, status_code) =
|
||||||
|
send_request_with_custom_auth(&app, "/indexes/doggo/search", &format!("Bearer {key}"))
|
||||||
|
.await;
|
||||||
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
|
snapshot!(response, @r###"
|
||||||
|
{
|
||||||
|
"message": "The API key cannot acces the index `doggo`, authorized indexes are [\"dog\"].",
|
||||||
|
"code": "invalid_api_key",
|
||||||
|
"type": "auth",
|
||||||
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[actix_rt::test]
|
||||||
|
async fn invalid_tenant_token() {
|
||||||
|
let server = Server::new_auth().await;
|
||||||
|
let app = server.init_web_app().await;
|
||||||
|
|
||||||
// The tenant token won't be recognized at all if we're not on a search route
|
// The tenant token won't be recognized at all if we're not on a search route
|
||||||
let claims = json!({ "tamo": "kefir" });
|
let claims = json!({ "tamo": "kefir" });
|
||||||
let jwt = jsonwebtoken::encode(&Header::default(), &claims, &EncodingKey::from_secret(b"tamo"))
|
let jwt = jsonwebtoken::encode(&Header::default(), &claims, &EncodingKey::from_secret(b"tamo"))
|
||||||
@ -527,7 +596,7 @@ async fn invalid_auth_format() {
|
|||||||
snapshot!(status_code, @"403 Forbidden");
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
snapshot!(response, @r###"
|
snapshot!(response, @r###"
|
||||||
{
|
{
|
||||||
"message": "Could not decode tenant token, JSON error: missing field `searchRules` at line 1 column 16",
|
"message": "Could not decode tenant token, JSON error: missing field `searchRules` at line 1 column 16.",
|
||||||
"code": "invalid_api_key",
|
"code": "invalid_api_key",
|
||||||
"type": "auth",
|
"type": "auth",
|
||||||
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
@ -543,7 +612,7 @@ async fn invalid_auth_format() {
|
|||||||
snapshot!(status_code, @"403 Forbidden");
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
snapshot!(response, @r###"
|
snapshot!(response, @r###"
|
||||||
{
|
{
|
||||||
"message": "Could not decode tenant token, JSON error: data did not match any variant of untagged enum SearchRules at line 1 column 23",
|
"message": "Could not decode tenant token, JSON error: data did not match any variant of untagged enum SearchRules at line 1 column 23.",
|
||||||
"code": "invalid_api_key",
|
"code": "invalid_api_key",
|
||||||
"type": "auth",
|
"type": "auth",
|
||||||
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
@ -559,12 +628,73 @@ async fn invalid_auth_format() {
|
|||||||
snapshot!(status_code, @"403 Forbidden");
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
snapshot!(response, @r###"
|
snapshot!(response, @r###"
|
||||||
{
|
{
|
||||||
"message": "Could not decode tenant token, InvalidSignature",
|
"message": "Could not decode tenant token, InvalidSignature.",
|
||||||
"code": "invalid_api_key",
|
"code": "invalid_api_key",
|
||||||
"type": "auth",
|
"type": "auth",
|
||||||
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
}
|
}
|
||||||
"###);
|
"###);
|
||||||
|
|
||||||
// ~~ For the next tests we first need to retrieve an API key
|
// ~~ For the next tests we first need a valid API key
|
||||||
|
let key = json!({ "actions": ["search"], "indexes": ["dog"], "expiresAt": null, "uid": uuid.to_string() });
|
||||||
|
let req = test::TestRequest::post()
|
||||||
|
.uri("/keys")
|
||||||
|
.insert_header(("Authorization", "Bearer MASTER_KEY"))
|
||||||
|
.set_json(&key)
|
||||||
|
.to_request();
|
||||||
|
let res = test::call_service(&app, req).await;
|
||||||
|
let body = test::read_body(res).await;
|
||||||
|
let response: Value = serde_json::from_slice(&body).unwrap_or_default();
|
||||||
|
snapshot!(json_string!(response, { ".createdAt" => "[date]", ".updatedAt" => "[date]" }), @r###"
|
||||||
|
{
|
||||||
|
"name": null,
|
||||||
|
"description": null,
|
||||||
|
"key": "aeb94973e0b6e912d94165430bbe87dee91a7c4f891ce19050c3910ec96977e9",
|
||||||
|
"uid": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"actions": [
|
||||||
|
"search"
|
||||||
|
],
|
||||||
|
"indexes": [
|
||||||
|
"dog"
|
||||||
|
],
|
||||||
|
"expiresAt": null,
|
||||||
|
"createdAt": "[date]",
|
||||||
|
"updatedAt": "[date]"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
let key = response["key"].as_str().unwrap();
|
||||||
|
|
||||||
|
let claims = json!({ "searchRules": ["doggo", "catto"], "apiKeyUid": uuid.to_string() });
|
||||||
|
let jwt = jsonwebtoken::encode(
|
||||||
|
&Header::default(),
|
||||||
|
&claims,
|
||||||
|
&EncodingKey::from_secret(key.as_bytes()),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
// Try to access an index that is not authorized by the tenant token
|
||||||
|
let (response, status_code) =
|
||||||
|
send_request_with_custom_auth(&app, "/indexes/dog/search", &format!("Bearer {jwt}")).await;
|
||||||
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
|
snapshot!(response, @r###"
|
||||||
|
{
|
||||||
|
"message": "The provided tenant token cannot acces the index `dog`, allowed indexes are [\"catto\", \"doggo\"].",
|
||||||
|
"code": "invalid_api_key",
|
||||||
|
"type": "auth",
|
||||||
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Try to access an index that *is* authorized by the tenant token but not by the api key used to generate the tt
|
||||||
|
let (response, status_code) =
|
||||||
|
send_request_with_custom_auth(&app, "/indexes/doggo/search", &format!("Bearer {jwt}"))
|
||||||
|
.await;
|
||||||
|
snapshot!(status_code, @"403 Forbidden");
|
||||||
|
snapshot!(response, @r###"
|
||||||
|
{
|
||||||
|
"message": "The API key used to generate this tenant token cannot acces the index `doggo`.",
|
||||||
|
"code": "invalid_api_key",
|
||||||
|
"type": "auth",
|
||||||
|
"link": "https://docs.meilisearch.com/errors#invalid_api_key"
|
||||||
|
}
|
||||||
|
"###);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user