@@ -30,25 +30,25 @@ use serde::Deserialize;
3030/// Request body for creating a new API key. `roles` is a set of role names
3131/// that must already exist in the tenant; permissions for the backing user
3232/// are derived from these roles (same flow as native/OAuth users).
33- /// `providedApiKey ` lets a caller register their own key; omitting it preserves
33+ /// `apiKey ` lets a caller register their own key; omitting it preserves
3434/// the existing server-generated key behavior.
3535#[ derive( Debug , Deserialize ) ]
36- #[ serde( rename_all = "camelCase" ) ]
36+ #[ serde( rename_all = "camelCase" , deny_unknown_fields ) ]
3737pub struct CreateApiKeyRequest {
3838 pub key_name : String ,
3939 #[ serde( default ) ]
4040 pub roles : HashSet < String > ,
41- pub provided_api_key : Option < String > ,
41+ pub api_key : Option < String > ,
42+ /// Helm uses this mode to request the server-managed global ingest role.
43+ #[ serde( default ) ]
44+ pub ingestor_only : bool ,
4245}
4346
44- /// Reject short or malformed caller-supplied credentials before persisting them.
45- pub fn validate_provided_api_key ( value : & str ) -> Result < ( ) , ApiKeyError > {
46- if !( 32 ..=256 ) . contains ( & value. len ( ) )
47- || !value
48- . bytes ( )
49- . all ( |byte| byte. is_ascii_alphanumeric ( ) || byte == b'-' || byte == b'_' )
50- {
51- return Err ( ApiKeyError :: InvalidProvidedApiKey ) ;
47+ /// Require a hyphenated UUID v4, allowing either letter case.
48+ pub fn validate_api_key ( value : & str ) -> Result < ( ) , ApiKeyError > {
49+ let uuid = uuid:: Uuid :: parse_str ( value) . map_err ( |_| ApiKeyError :: InvalidApiKey ) ?;
50+ if value. len ( ) != 36 || uuid. get_version_num ( ) != 4 {
51+ return Err ( ApiKeyError :: InvalidApiKey ) ;
5252 }
5353 Ok ( ( ) )
5454}
@@ -64,8 +64,11 @@ pub enum ApiKeyError {
6464 #[ error( "API key value is already registered" ) ]
6565 DuplicateApiKey ,
6666
67- #[ error( "providedApiKey must be 32-256 ASCII letters, digits, hyphens, or underscores" ) ]
68- InvalidProvidedApiKey ,
67+ #[ error( "apiKey must be a UUID v4 in 8-4-4-4-12 format" ) ]
68+ InvalidApiKey ,
69+
70+ #[ error( "ingestorOnly cannot be combined with roles" ) ]
71+ IngestorOnlyWithRoles ,
6972
7073 #[ error( "Unauthorized: {0}" ) ]
7174 Unauthorized ( String ) ,
@@ -90,7 +93,9 @@ impl actix_web::ResponseError for ApiKeyError {
9093 ApiKeyError :: DuplicateKeyName ( _) | ApiKeyError :: DuplicateApiKey => {
9194 actix_web:: http:: StatusCode :: CONFLICT
9295 }
93- ApiKeyError :: InvalidProvidedApiKey => actix_web:: http:: StatusCode :: BAD_REQUEST ,
96+ ApiKeyError :: InvalidApiKey | ApiKeyError :: IngestorOnlyWithRoles => {
97+ actix_web:: http:: StatusCode :: BAD_REQUEST
98+ }
9499 ApiKeyError :: Unauthorized ( _) => actix_web:: http:: StatusCode :: FORBIDDEN ,
95100 ApiKeyError :: RevocationSyncFailed ( _) => {
96101 actix_web:: http:: StatusCode :: SERVICE_UNAVAILABLE
0 commit comments