@@ -15,19 +15,21 @@ use axum::{
15
15
Method , StatusCode , Uri ,
16
16
} ,
17
17
response:: { IntoResponse , Response } ,
18
- Router ,
18
+ RequestExt , Router ,
19
19
} ;
20
20
use itertools:: Itertools ;
21
21
use tokio:: sync:: RwLock ;
22
22
use tracing:: { trace, warn} ;
23
23
24
24
use crate :: {
25
25
container_orchestrator:: { ContainerOrchestrator , PublishedContainer } ,
26
- registry:: { storage:: ImageLocation , ManifestReference , Reference } ,
26
+ registry:: {
27
+ storage:: ImageLocation , AuthProvider , ManifestReference , Reference , UnverifiedCredentials ,
28
+ } ,
27
29
} ;
28
30
29
- #[ derive( Debug ) ]
30
31
pub ( crate ) struct ReverseProxy {
32
+ auth_provider : Arc < dyn AuthProvider > ,
31
33
client : reqwest:: Client ,
32
34
routing_table : RwLock < RoutingTable > ,
33
35
orchestrator : OnceLock < Arc < ContainerOrchestrator > > ,
@@ -173,6 +175,7 @@ enum AppError {
173
175
InternalUrlInvalid ,
174
176
AssertionFailed ( & ' static str ) ,
175
177
NonUtf8Header ,
178
+ AuthFailure ( StatusCode ) ,
176
179
Internal ( anyhow:: Error ) ,
177
180
}
178
181
@@ -184,6 +187,7 @@ impl Display for AppError {
184
187
AppError :: InternalUrlInvalid => f. write_str ( "internal url invalid" ) ,
185
188
AppError :: AssertionFailed ( msg) => f. write_str ( msg) ,
186
189
AppError :: NonUtf8Header => f. write_str ( "a header contained non-utf8 data" ) ,
190
+ AppError :: AuthFailure ( _) => f. write_str ( "authentication missing or not present" ) ,
187
191
AppError :: Internal ( err) => Display :: fmt ( err, f) ,
188
192
}
189
193
}
@@ -207,6 +211,7 @@ impl IntoResponse for AppError {
207
211
AppError :: InternalUrlInvalid => StatusCode :: NOT_FOUND . into_response ( ) ,
208
212
AppError :: AssertionFailed ( msg) => ( StatusCode :: NOT_FOUND , msg) . into_response ( ) ,
209
213
AppError :: NonUtf8Header => StatusCode :: BAD_REQUEST . into_response ( ) ,
214
+ AppError :: AuthFailure ( status) => status. into_response ( ) ,
210
215
AppError :: Internal ( err) => {
211
216
( StatusCode :: INTERNAL_SERVER_ERROR , err. to_string ( ) ) . into_response ( )
212
217
}
@@ -215,8 +220,9 @@ impl IntoResponse for AppError {
215
220
}
216
221
217
222
impl ReverseProxy {
218
- pub ( crate ) fn new ( ) -> Arc < Self > {
223
+ pub ( crate ) fn new ( auth_provider : Arc < dyn AuthProvider > ) -> Arc < Self > {
219
224
Arc :: new ( ReverseProxy {
225
+ auth_provider,
220
226
client : reqwest:: Client :: new ( ) ,
221
227
routing_table : RwLock :: new ( Default :: default ( ) ) ,
222
228
orchestrator : OnceLock :: new ( ) ,
@@ -240,6 +246,7 @@ impl ReverseProxy {
240
246
pub ( crate ) fn set_orchestrator ( & self , orchestrator : Arc < ContainerOrchestrator > ) -> & Self {
241
247
self . orchestrator
242
248
. set ( orchestrator)
249
+ . map_err ( |_| ( ) )
243
250
. expect ( "set already set orchestrator" ) ;
244
251
self
245
252
}
@@ -271,7 +278,18 @@ async fn route_request(
271
278
let dest = match dest_uri {
272
279
Destination :: ReverseProxied ( dest) => dest,
273
280
Destination :: Internal ( uri) => {
274
- todo ! ( "check access (master password)" ) ;
281
+ let method = request. method ( ) . clone ( ) ;
282
+ // Note: The auth functionality has been lifted from `registry`. It may need to be
283
+ // refactored out because of that.
284
+ let creds = request
285
+ . extract :: < UnverifiedCredentials , _ > ( )
286
+ . await
287
+ . map_err ( AppError :: AuthFailure ) ?;
288
+
289
+ // Any internal URL is subject to requiring auth through the master key.
290
+ if !rp. auth_provider . check_credentials ( & creds) . await {
291
+ todo ! ( "return 403" ) ;
292
+ }
275
293
276
294
let remainder = uri
277
295
. path ( )
@@ -297,7 +315,7 @@ async fn route_request(
297
315
. get ( )
298
316
. ok_or_else ( || AppError :: AssertionFailed ( "no orchestrator configured" ) ) ?;
299
317
300
- return match * request . method ( ) {
318
+ return match method {
301
319
Method :: GET => {
302
320
let config = orchestrator
303
321
. load_config ( & manifest_reference)
0 commit comments