feat(ui): implement scoped key creation on search UI enable (P5.21.a)
Implements plan §13.21 auth model layer 1 - when search UI is first enabled for an index, the orchestrator now creates a scoped search-only key on every Meilisearch node via POST /keys with actions: [search], indexes scoped. The key is stored in Redis hash with metadata (primary_uid, rotated_at, generation) for retrieval at request time. Changes: - Add imports for MeilisearchClient and mint_scoped_key - Implement get_or_create_scoped_key to create keys when needed - Store new keys in Redis via set_search_ui_scoped_key - Return the scoped key for use in JWT session minting The scoped key has a hard expiration of scoped_key_max_age_days (60d default) and will be auto-rotated by the background rotation loop at scoped_key_rotate_before_expiry_days (30d default) - see P10.5 for the rotation coordination implementation. Closes: miroir-uhj.21.1
This commit is contained in:
parent
ad1c9d011c
commit
ecb27e78ff
1 changed files with 35 additions and 7 deletions
|
|
@ -21,9 +21,11 @@ use crate::error_response::ErrorResponse;
|
|||
use rust_embed::RustEmbed as Embed;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::auth::{build_csp_header, jwt_encode, JwtClaims, JwtHeader, KID_PRIMARY};
|
||||
use crate::routes::indexes::MeilisearchClient;
|
||||
use crate::scoped_key_rotation::mint_scoped_key;
|
||||
|
||||
use super::admin_endpoints::AppState;
|
||||
|
||||
|
|
@ -331,12 +333,38 @@ async fn get_or_create_scoped_key(
|
|||
);
|
||||
}
|
||||
|
||||
// TODO: Create new scoped key via Meilisearch API
|
||||
// For now, return an error indicating the key needs to be created
|
||||
Err(ErrorResponse::internal_error(format!(
|
||||
"scoped key for index '{}' needs to be created via background rotation",
|
||||
index_uid
|
||||
)))
|
||||
// Create new scoped key via Meilisearch API (plan §13.21)
|
||||
info!(index = %index_uid, "creating new scoped search-only key");
|
||||
|
||||
let client = MeilisearchClient::new(state.config.node_master_key.clone());
|
||||
let (new_key, new_uid) = mint_scoped_key(&client, &state.config, index_uid)
|
||||
.await
|
||||
.map_err(|e| ErrorResponse::internal_error(format!("failed to mint scoped key: {}", e)))?;
|
||||
|
||||
let now_ms = chrono::Utc::now().timestamp_millis();
|
||||
let scoped_key = SearchUiScopedKey {
|
||||
index_uid: index_uid.to_string(),
|
||||
primary_key: new_key.clone(),
|
||||
primary_uid: new_uid.clone(),
|
||||
previous_key: None,
|
||||
previous_uid: None,
|
||||
rotated_at: now_ms,
|
||||
generation: 1,
|
||||
};
|
||||
|
||||
// Store in Redis
|
||||
redis_store
|
||||
.set_search_ui_scoped_key(&scoped_key)
|
||||
.map_err(|e| ErrorResponse::internal_error(format!("failed to store scoped key: {}", e)))?;
|
||||
|
||||
info!(
|
||||
index = %index_uid,
|
||||
uid = %new_uid,
|
||||
generation = 1,
|
||||
"created new scoped search-only key"
|
||||
);
|
||||
|
||||
Ok(scoped_key)
|
||||
}
|
||||
|
||||
/// Get per-index search UI configuration (plan §13.21).
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue