mirror of
https://github.com/meilisearch/MeiliSearch
synced 2025-07-04 12:27:13 +02:00
Add uid and name fields in keys
This commit is contained in:
parent
e2c204cf86
commit
96a5791e39
9 changed files with 205 additions and 177 deletions
|
@ -132,6 +132,7 @@ pub mod policies {
|
|||
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use time::OffsetDateTime;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::extractors::authentication::Policy;
|
||||
use meilisearch_auth::{Action, AuthController, AuthFilter, SearchRules};
|
||||
|
@ -146,16 +147,16 @@ pub mod policies {
|
|||
validation
|
||||
}
|
||||
|
||||
/// Extracts the key prefix used to sign the payload from the payload, without performing any validation.
|
||||
fn extract_key_prefix(token: &str) -> Option<String> {
|
||||
/// Extracts the key id used to sign the payload from the payload, without performing any validation.
|
||||
fn extract_key_id(token: &str) -> Option<Uuid> {
|
||||
let mut validation = tenant_token_validation();
|
||||
validation.insecure_disable_signature_validation();
|
||||
let dummy_key = DecodingKey::from_secret(b"secret");
|
||||
let token_data = decode::<Claims>(token, &dummy_key, &validation).ok()?;
|
||||
|
||||
// get token fields without validating it.
|
||||
let Claims { api_key_prefix, .. } = token_data.claims;
|
||||
Some(api_key_prefix)
|
||||
let Claims { uid, .. } = token_data.claims;
|
||||
Some(uid)
|
||||
}
|
||||
|
||||
pub struct MasterPolicy;
|
||||
|
@ -195,8 +196,10 @@ pub mod policies {
|
|||
return Some(filters);
|
||||
} else if let Some(action) = Action::from_repr(A) {
|
||||
// API key
|
||||
if let Ok(true) = auth.authenticate(token.as_bytes(), action, index) {
|
||||
return auth.get_key_filters(token, None).ok();
|
||||
if let Ok(Some(uid)) = auth.get_uid_from_sha(token.as_bytes()) {
|
||||
if let Ok(true) = auth.is_key_authorized(uid, action, index) {
|
||||
return auth.get_key_filters(uid, None).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,14 +218,11 @@ pub mod policies {
|
|||
return None;
|
||||
}
|
||||
|
||||
let api_key_prefix = extract_key_prefix(token)?;
|
||||
let uid = extract_key_id(token)?;
|
||||
// check if parent key is authorized to do the action.
|
||||
if auth
|
||||
.is_key_authorized(api_key_prefix.as_bytes(), Action::Search, index)
|
||||
.ok()?
|
||||
{
|
||||
if auth.is_key_authorized(uid, Action::Search, index).ok()? {
|
||||
// Check if tenant token is valid.
|
||||
let key = auth.generate_key(&api_key_prefix)?;
|
||||
let key = auth.generate_key(uid)?;
|
||||
let data = decode::<Claims>(
|
||||
token,
|
||||
&DecodingKey::from_secret(key.as_bytes()),
|
||||
|
@ -245,7 +245,7 @@ pub mod policies {
|
|||
}
|
||||
|
||||
return auth
|
||||
.get_key_filters(api_key_prefix, Some(data.claims.search_rules))
|
||||
.get_key_filters(uid, Some(data.claims.search_rules))
|
||||
.ok();
|
||||
}
|
||||
|
||||
|
@ -258,6 +258,6 @@ pub mod policies {
|
|||
struct Claims {
|
||||
search_rules: SearchRules,
|
||||
exp: Option<i64>,
|
||||
api_key_prefix: String,
|
||||
uid: Uuid,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::str;
|
||||
use uuid::Uuid;
|
||||
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
|
||||
|
@ -20,7 +21,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
|||
.route(web::get().to(SeqHandler(list_api_keys))),
|
||||
)
|
||||
.service(
|
||||
web::resource("/{api_key}")
|
||||
web::resource("/{key}")
|
||||
.route(web::get().to(SeqHandler(get_api_key)))
|
||||
.route(web::patch().to(SeqHandler(patch_api_key)))
|
||||
.route(web::delete().to(SeqHandler(delete_api_key))),
|
||||
|
@ -65,9 +66,12 @@ pub async fn get_api_key(
|
|||
auth_controller: GuardedData<MasterPolicy, AuthController>,
|
||||
path: web::Path<AuthParam>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
let api_key = path.into_inner().api_key;
|
||||
let key = path.into_inner().key;
|
||||
|
||||
let res = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> {
|
||||
let key = auth_controller.get_key(&api_key)?;
|
||||
let uid = Uuid::parse_str(&key).or_else(|_| auth_controller.try_get_uid_from_sha(&key))?;
|
||||
let key = auth_controller.get_key(uid)?;
|
||||
|
||||
Ok(KeyView::from_key(key, &auth_controller))
|
||||
})
|
||||
.await
|
||||
|
@ -81,10 +85,12 @@ pub async fn patch_api_key(
|
|||
body: web::Json<Value>,
|
||||
path: web::Path<AuthParam>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
let api_key = path.into_inner().api_key;
|
||||
let key = path.into_inner().key;
|
||||
let body = body.into_inner();
|
||||
let res = tokio::task::spawn_blocking(move || -> Result<_, AuthControllerError> {
|
||||
let key = auth_controller.update_key(&api_key, body)?;
|
||||
let uid = Uuid::parse_str(&key).or_else(|_| auth_controller.try_get_uid_from_sha(&key))?;
|
||||
let key = auth_controller.update_key(uid, body)?;
|
||||
|
||||
Ok(KeyView::from_key(key, &auth_controller))
|
||||
})
|
||||
.await
|
||||
|
@ -97,24 +103,29 @@ pub async fn delete_api_key(
|
|||
auth_controller: GuardedData<MasterPolicy, AuthController>,
|
||||
path: web::Path<AuthParam>,
|
||||
) -> Result<HttpResponse, ResponseError> {
|
||||
let api_key = path.into_inner().api_key;
|
||||
tokio::task::spawn_blocking(move || auth_controller.delete_key(&api_key))
|
||||
.await
|
||||
.map_err(|e| ResponseError::from_msg(e.to_string(), Code::Internal))??;
|
||||
let key = path.into_inner().key;
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let uid = Uuid::parse_str(&key).or_else(|_| auth_controller.try_get_uid_from_sha(&key))?;
|
||||
auth_controller.delete_key(uid)
|
||||
})
|
||||
.await
|
||||
.map_err(|e| ResponseError::from_msg(e.to_string(), Code::Internal))??;
|
||||
|
||||
Ok(HttpResponse::NoContent().finish())
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AuthParam {
|
||||
api_key: String,
|
||||
key: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct KeyView {
|
||||
name: Option<String>,
|
||||
description: Option<String>,
|
||||
key: String,
|
||||
uid: Uuid,
|
||||
actions: Vec<Action>,
|
||||
indexes: Vec<String>,
|
||||
#[serde(serialize_with = "time::serde::rfc3339::option::serialize")]
|
||||
|
@ -127,12 +138,13 @@ struct KeyView {
|
|||
|
||||
impl KeyView {
|
||||
fn from_key(key: Key, auth: &AuthController) -> Self {
|
||||
let key_id = str::from_utf8(&key.id).unwrap();
|
||||
let generated_key = auth.generate_key(key_id).unwrap_or_default();
|
||||
let generated_key = auth.generate_key(key.uid).unwrap_or_default();
|
||||
|
||||
KeyView {
|
||||
name: key.name,
|
||||
description: key.description,
|
||||
key: generated_key,
|
||||
uid: key.uid,
|
||||
actions: key.actions,
|
||||
indexes: key.indexes,
|
||||
expires_at: key.expires_at,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue