@@ -3,6 +3,7 @@ use std::sync::Arc;
33use collection:: operations:: shard_selector_internal:: ShardSelectorInternal ;
44use collection:: operations:: types:: ScrollRequestInternal ;
55use common:: counter:: hardware_accumulator:: HwMeasurementAcc ;
6+ use itertools:: Itertools ;
67use segment:: types:: { WithPayloadInterface , WithVector } ;
78use storage:: content_manager:: errors:: StorageError ;
89use storage:: content_manager:: toc:: TableOfContent ;
@@ -24,12 +25,18 @@ pub struct AuthKeys {
2425 /// A key allowing Read or Write operations
2526 read_write : Option < String > ,
2627
28+ /// Alternative to `read_write` key
29+ alt_read_write : Option < String > ,
30+
2731 /// A key allowing Read operations
2832 read_only : Option < String > ,
2933
3034 /// A JWT parser, based on the read_write key
3135 jwt_parser : Option < JwtParser > ,
3236
37+ /// Alternative JWT parser, based on the alt_read_write key
38+ alt_jwt_parser : Option < JwtParser > ,
39+
3340 /// Table of content, needed to do stateful validation of JWT
3441 toc : Arc < TableOfContent > ,
3542}
@@ -42,14 +49,20 @@ pub enum AuthError {
4249}
4350
4451impl AuthKeys {
45- fn get_jwt_parser ( service_config : & ServiceConfig ) -> Option < JwtParser > {
52+ fn get_jwt_parser ( service_config : & ServiceConfig ) -> ( Option < JwtParser > , Option < JwtParser > ) {
4653 if service_config. jwt_rbac . unwrap_or_default ( ) {
47- service_config
48- . api_key
49- . as_ref ( )
50- . map ( |secret| JwtParser :: new ( secret) )
54+ (
55+ service_config
56+ . api_key
57+ . as_ref ( )
58+ . map ( |secret| JwtParser :: new ( secret) ) ,
59+ service_config
60+ . alt_api_key
61+ . as_ref ( )
62+ . map ( |secret| JwtParser :: new ( secret) ) ,
63+ )
5164 } else {
52- None
65+ ( None , None )
5366 }
5467 }
5568
@@ -59,15 +72,22 @@ impl AuthKeys {
5972 pub fn try_create ( service_config : & ServiceConfig , toc : Arc < TableOfContent > ) -> Option < Self > {
6073 match (
6174 service_config. api_key . clone ( ) ,
75+ service_config. alt_api_key . clone ( ) ,
6276 service_config. read_only_api_key . clone ( ) ,
6377 ) {
64- ( None , None ) => None ,
65- ( read_write, read_only) => Some ( Self {
66- read_write,
67- read_only,
68- jwt_parser : Self :: get_jwt_parser ( service_config) ,
69- toc,
70- } ) ,
78+ ( None , None , None ) => None ,
79+ ( read_write, alt_read_write, read_only) => {
80+ let ( jwt_parser, alt_jwt_parser) = Self :: get_jwt_parser ( service_config) ;
81+
82+ Some ( Self {
83+ read_write,
84+ alt_read_write,
85+ read_only,
86+ jwt_parser,
87+ alt_jwt_parser,
88+ toc,
89+ } )
90+ }
7191 }
7292 }
7393
@@ -98,13 +118,20 @@ impl AuthKeys {
98118 ) ) ;
99119 }
100120
101- if let Some ( claims) = self . jwt_parser . as_ref ( ) . and_then ( |p| p. decode ( key) ) {
121+ let ( claims, errors) : ( Vec < _ > , Vec < _ > ) =
122+ [ self . jwt_parser . as_ref ( ) , self . alt_jwt_parser . as_ref ( ) ]
123+ . into_iter ( )
124+ . flatten ( )
125+ . filter_map ( |p| p. decode ( key) )
126+ . partition_result ( ) ;
127+
128+ if let Some ( claims) = claims. into_iter ( ) . next ( ) {
102129 let Claims {
103130 sub,
104131 exp : _, // already validated on decoding
105132 access,
106133 value_exists,
107- } = claims? ;
134+ } = claims;
108135
109136 if let Some ( value_exists) = value_exists {
110137 self . validate_value_exists ( & value_exists) . await ?;
@@ -113,6 +140,12 @@ impl AuthKeys {
113140 return Ok ( ( access, InferenceToken ( sub) ) ) ;
114141 }
115142
143+ // JTW parser exists, but can't decode the token
144+ if let Some ( error) = errors. into_iter ( ) . next ( ) {
145+ return Err ( error) ;
146+ }
147+
148+ // No JTW parser configured
116149 Err ( AuthError :: Unauthorized (
117150 "Invalid API key or JWT" . to_string ( ) ,
118151 ) )
@@ -167,8 +200,14 @@ impl AuthKeys {
167200 /// Check if a key is allowed to write
168201 #[ inline]
169202 fn can_write ( & self , key : & str ) -> bool {
170- self . read_write
203+ let can_write = self
204+ . read_write
205+ . as_ref ( )
206+ . is_some_and ( |rw_key| ct_eq ( rw_key, key) ) ;
207+ let alt_can_write = self
208+ . alt_read_write
171209 . as_ref ( )
172- . is_some_and ( |rw_key| ct_eq ( rw_key, key) )
210+ . is_some_and ( |alt_rw_key| ct_eq ( alt_rw_key, key) ) ;
211+ can_write || alt_can_write
173212 }
174213}
0 commit comments