Skip to content

Commit 1efdd58

Browse files
authored
Merge pull request #336 from umccr/feat/generalized-auth
feat: generalized auth
2 parents a6bd439 + 13427c2 commit 1efdd58

File tree

44 files changed

+2701
-1266
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2701
-1266
lines changed

Cargo.lock

Lines changed: 369 additions & 435 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

htsget-actix/src/handlers/get.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use std::collections::HashMap;
22

3+
use actix_web::web::ReqData;
34
use actix_web::{
45
HttpRequest, Responder,
56
web::{Data, Path, Query},
67
};
78
use htsget_http::{Endpoint, get};
89
use htsget_search::HtsGet;
10+
use serde_json::Value;
911
use tracing::info;
1012
use tracing::instrument;
1113

@@ -19,6 +21,7 @@ pub async fn reads<H: HtsGet + Clone + Send + Sync + 'static>(
1921
request: Query<HashMap<String, String>>,
2022
path: Path<String>,
2123
http_request: HttpRequest,
24+
extension: Option<ReqData<Value>>,
2225
app_state: Data<AppState<H>>,
2326
) -> impl Responder {
2427
let request = extract_request(request, path, http_request);
@@ -31,6 +34,7 @@ pub async fn reads<H: HtsGet + Clone + Send + Sync + 'static>(
3134
request,
3235
Endpoint::Reads,
3336
app_state.auth.clone(),
37+
extension.map(|extension| extension.into_inner()),
3438
)
3539
.await,
3640
)
@@ -42,6 +46,7 @@ pub async fn variants<H: HtsGet + Clone + Send + Sync + 'static>(
4246
request: Query<HashMap<String, String>>,
4347
path: Path<String>,
4448
http_request: HttpRequest,
49+
extension: Option<ReqData<Value>>,
4550
app_state: Data<AppState<H>>,
4651
) -> impl Responder {
4752
let request = extract_request(request, path, http_request);
@@ -54,6 +59,7 @@ pub async fn variants<H: HtsGet + Clone + Send + Sync + 'static>(
5459
request,
5560
Endpoint::Variants,
5661
app_state.auth.clone(),
62+
extension.map(|extension| extension.into_inner()),
5763
)
5864
.await,
5965
)

htsget-actix/src/handlers/post.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use std::collections::HashMap;
22

3-
use actix_web::web::Query;
3+
use actix_web::web::{Query, ReqData};
44
use actix_web::{
55
HttpRequest, Responder,
66
web::{Data, Json, Path},
77
};
88
use htsget_http::{Endpoint, PostRequest, post};
99
use htsget_search::HtsGet;
10+
use serde_json::Value;
1011
use tracing::info;
1112
use tracing::instrument;
1213

@@ -19,6 +20,7 @@ pub async fn reads<H: HtsGet + Clone + Send + Sync + 'static>(
1920
request: Query<HashMap<String, String>>,
2021
path: Path<String>,
2122
http_request: HttpRequest,
23+
extension: Option<ReqData<Value>>,
2224
body: Json<PostRequest>,
2325
app_state: Data<AppState<H>>,
2426
) -> impl Responder {
@@ -33,6 +35,7 @@ pub async fn reads<H: HtsGet + Clone + Send + Sync + 'static>(
3335
request,
3436
Endpoint::Reads,
3537
app_state.auth.clone(),
38+
extension.map(|extension| extension.into_inner()),
3639
)
3740
.await,
3841
)
@@ -44,6 +47,7 @@ pub async fn variants<H: HtsGet + Clone + Send + Sync + 'static>(
4447
request: Query<HashMap<String, String>>,
4548
path: Path<String>,
4649
http_request: HttpRequest,
50+
extension: Option<ReqData<Value>>,
4751
body: Json<PostRequest>,
4852
app_state: Data<AppState<H>>,
4953
) -> impl Responder {
@@ -58,6 +62,7 @@ pub async fn variants<H: HtsGet + Clone + Send + Sync + 'static>(
5862
request,
5963
Endpoint::Variants,
6064
app_state.auth.clone(),
65+
extension.map(|extension| extension.into_inner()),
6166
)
6267
.await,
6368
)

htsget-actix/src/lib.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,11 @@ mod tests {
186186
use actix_web::dev::ServiceResponse;
187187
use actix_web::{App, test, web};
188188
use async_trait::async_trait;
189-
use htsget_test::http::auth::create_test_auth_config;
189+
use htsget_test::http::auth::{
190+
create_test_auth_config, mock_id_test, mock_prefix_test, mock_regex_test,
191+
};
190192
use rustls::crypto::aws_lc_rs;
193+
use serde_json::Value;
191194
use tempfile::TempDir;
192195

193196
use crate::Config;
@@ -321,8 +324,8 @@ mod tests {
321324
}
322325
}
323326

324-
async fn new_with_auth(public_key: Vec<u8>, suppressed: bool) -> Self {
325-
let mock_server = MockAuthServer::new().await;
327+
async fn new_with_auth(public_key: Vec<u8>, suppressed: bool, mock_location: Value) -> Self {
328+
let mock_server = MockAuthServer::new(mock_location).await;
326329
let auth_config = create_test_auth_config(&mock_server, public_key, suppressed);
327330
let auth = AuthBuilder::default()
328331
.with_config(auth_config.clone())
@@ -437,16 +440,38 @@ mod tests {
437440
async fn test_auth_insufficient_permissions() {
438441
let (private_key, public_key) = generate_key_pair();
439442

440-
let server = ActixTestServer::new_with_auth(public_key, false).await;
443+
let server = ActixTestServer::new_with_auth(public_key, false, mock_id_test()).await;
441444
auth::test_auth_insufficient_permissions::<JsonResponse, _>(&server, private_key).await;
442445
}
443446

444447
#[actix_web::test]
445-
async fn test_auth_succeeds() {
448+
async fn test_auth_succeeds_id() {
449+
let (private_key, public_key) = generate_key_pair();
450+
451+
auth::test_auth_succeeds::<JsonResponse, _>(
452+
&ActixTestServer::new_with_auth(public_key, false, mock_id_test()).await,
453+
private_key,
454+
)
455+
.await;
456+
}
457+
458+
#[actix_web::test]
459+
async fn test_auth_succeeds_prefix() {
460+
let (private_key, public_key) = generate_key_pair();
461+
462+
auth::test_auth_succeeds::<JsonResponse, _>(
463+
&ActixTestServer::new_with_auth(public_key, false, mock_prefix_test()).await,
464+
private_key,
465+
)
466+
.await;
467+
}
468+
469+
#[actix_web::test]
470+
async fn test_auth_succeeds_regex() {
446471
let (private_key, public_key) = generate_key_pair();
447472

448473
auth::test_auth_succeeds::<JsonResponse, _>(
449-
&ActixTestServer::new_with_auth(public_key, false).await,
474+
&ActixTestServer::new_with_auth(public_key, false, mock_regex_test()).await,
450475
private_key,
451476
)
452477
.await;
@@ -457,7 +482,7 @@ mod tests {
457482
async fn test_auth_insufficient_permissions_suppressed() {
458483
let (private_key, public_key) = generate_key_pair();
459484

460-
let server = ActixTestServer::new_with_auth(public_key, true).await;
485+
let server = ActixTestServer::new_with_auth(public_key, true, mock_id_test()).await;
461486
auth::test_auth_insufficient_permissions::<JsonResponse, _>(&server, private_key).await;
462487
}
463488

@@ -467,7 +492,7 @@ mod tests {
467492
let (private_key, public_key) = generate_key_pair();
468493

469494
auth::test_auth_succeeds::<JsonResponse, _>(
470-
&ActixTestServer::new_with_auth(public_key, true).await,
495+
&ActixTestServer::new_with_auth(public_key, true, mock_id_test()).await,
471496
private_key,
472497
)
473498
.await;

htsget-axum/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ default = []
3434

3535
[dependencies]
3636
# Axum server
37+
serde_json = "1"
3738
hyper = { version = "1", features = ["http1", "http2", "server"] }
3839
rustls = "0.23"
3940
hyper-util = "0.1"

htsget-axum/src/handlers/get.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1+
use crate::server::AppState;
2+
use axum::Extension;
13
use axum::extract::{Path, Query, State};
24
use axum::response::IntoResponse;
35
use htsget_http::{Endpoint, get};
46
use htsget_search::HtsGet;
57
use http::HeaderMap;
8+
use serde_json::Value;
69
use std::collections::HashMap;
710

8-
use crate::server::AppState;
9-
1011
use super::{extract_request, handle_response};
1112

1213
/// GET request reads endpoint.
1314
pub async fn reads<H: HtsGet + Send + Sync + 'static>(
1415
query: Query<HashMap<String, String>>,
1516
path: Path<String>,
1617
headers: HeaderMap,
18+
extension: Option<Extension<Value>>,
1719
State(app_state): State<AppState<H>>,
1820
) -> impl IntoResponse {
1921
let request = extract_request(query, path, headers);
@@ -24,6 +26,7 @@ pub async fn reads<H: HtsGet + Send + Sync + 'static>(
2426
request,
2527
Endpoint::Reads,
2628
app_state.auth_middleware,
29+
extension.map(|extension| extension.0),
2730
)
2831
.await,
2932
)
@@ -34,6 +37,7 @@ pub async fn variants<H: HtsGet + Send + Sync + 'static>(
3437
request: Query<HashMap<String, String>>,
3538
path: Path<String>,
3639
headers: HeaderMap,
40+
extension: Option<Extension<Value>>,
3741
State(app_state): State<AppState<H>>,
3842
) -> impl IntoResponse {
3943
let request = extract_request(request, path, headers);
@@ -44,6 +48,7 @@ pub async fn variants<H: HtsGet + Send + Sync + 'static>(
4448
request,
4549
Endpoint::Variants,
4650
app_state.auth_middleware,
51+
extension.map(|extension| extension.0),
4752
)
4853
.await,
4954
)

htsget-axum/src/handlers/post.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1-
use axum::Json;
1+
use crate::server::AppState;
22
use axum::extract::{Path, Query, State};
33
use axum::response::IntoResponse;
4+
use axum::{Extension, Json};
45
use htsget_http::{Endpoint, PostRequest, post};
56
use htsget_search::HtsGet;
67
use http::HeaderMap;
8+
use serde_json::Value;
79
use std::collections::HashMap;
810

9-
use crate::server::AppState;
10-
1111
use super::{extract_request, handle_response};
1212

1313
/// POST request reads endpoint.
1414
pub async fn reads<H: HtsGet + Clone + Send + Sync + 'static>(
1515
request: Query<HashMap<String, String>>,
1616
path: Path<String>,
1717
headers: HeaderMap,
18+
extension: Option<Extension<Value>>,
1819
State(app_state): State<AppState<H>>,
1920
Json(body): Json<PostRequest>,
2021
) -> impl IntoResponse {
@@ -27,6 +28,7 @@ pub async fn reads<H: HtsGet + Clone + Send + Sync + 'static>(
2728
request,
2829
Endpoint::Reads,
2930
app_state.auth_middleware,
31+
extension.map(|extension| extension.0),
3032
)
3133
.await,
3234
)
@@ -37,6 +39,7 @@ pub async fn variants<H: HtsGet + Clone + Send + Sync + 'static>(
3739
request: Query<HashMap<String, String>>,
3840
path: Path<String>,
3941
headers: HeaderMap,
42+
extension: Option<Extension<Value>>,
4043
State(app_state): State<AppState<H>>,
4144
Json(body): Json<PostRequest>,
4245
) -> impl IntoResponse {
@@ -49,6 +52,7 @@ pub async fn variants<H: HtsGet + Clone + Send + Sync + 'static>(
4952
request,
5053
Endpoint::Variants,
5154
app_state.auth_middleware,
55+
extension.map(|extension| extension.0),
5256
)
5357
.await,
5458
)

htsget-axum/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub use axum::Router;
2+
13
pub mod error;
24
pub mod handlers;
35
pub mod middleware;

htsget-axum/src/server/data.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,13 @@ impl DataServer {
5050
// The auth layer needs to be added first so that layers like the CorsLayer
5151
// can respond to `Options` requests first and without auth.
5252
router = if let Some(auth) = auth {
53-
router.layer(AuthenticationLayer::from(
54-
AuthBuilder::default().with_config(auth).build()?,
55-
))
53+
if auth.auth_mode().is_some() {
54+
router.layer(AuthenticationLayer::from(
55+
AuthBuilder::default().with_config(auth).build()?,
56+
))
57+
} else {
58+
router
59+
}
5660
} else {
5761
router
5862
};

htsget-axum/src/server/ticket.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ mod tests {
151151
use htsget_config::config::Config;
152152
use htsget_config::storage::file::default_path;
153153
use htsget_config::types::JsonResponse;
154-
use htsget_test::http::auth::{MockAuthServer, create_test_auth_config};
154+
use htsget_test::http::auth::{
155+
MockAuthServer, create_test_auth_config, mock_id_test, mock_prefix_test, mock_regex_test,
156+
};
155157
use htsget_test::http::server::expected_url_path;
156158
use htsget_test::http::{
157159
Header, Response as TestResponse, TestRequest, TestServer, auth, config_with_tls, cors,
@@ -161,6 +163,7 @@ mod tests {
161163
use http::header::HeaderName;
162164
use http::{Method, Request};
163165
use rustls::crypto::aws_lc_rs;
166+
use serde_json::Value;
164167
use tempfile::TempDir;
165168
use tower::ServiceExt;
166169

@@ -264,8 +267,8 @@ mod tests {
264267
}
265268
}
266269

267-
async fn new_with_auth(public_key: Vec<u8>, suppressed: bool) -> Self {
268-
let mock_server = MockAuthServer::new().await;
270+
async fn new_with_auth(public_key: Vec<u8>, suppressed: bool, mock_location: Value) -> Self {
271+
let mock_server = MockAuthServer::new(mock_location).await;
269272
let auth_config = create_test_auth_config(&mock_server, public_key, suppressed);
270273
let config = default_test_config(Some(auth_config));
271274

@@ -374,16 +377,38 @@ mod tests {
374377
async fn test_auth_insufficient_permissions() {
375378
let (private_key, public_key) = generate_key_pair();
376379

377-
let server = AxumTestServer::new_with_auth(public_key, false).await;
380+
let server = AxumTestServer::new_with_auth(public_key, false, mock_id_test()).await;
378381
auth::test_auth_insufficient_permissions::<JsonResponse, _>(&server, private_key).await;
379382
}
380383

381384
#[tokio::test]
382-
async fn test_auth_succeeds() {
385+
async fn test_auth_succeeds_id() {
386+
let (private_key, public_key) = generate_key_pair();
387+
388+
auth::test_auth_succeeds::<JsonResponse, _>(
389+
&AxumTestServer::new_with_auth(public_key, false, mock_id_test()).await,
390+
private_key,
391+
)
392+
.await;
393+
}
394+
395+
#[tokio::test]
396+
async fn test_auth_succeeds_prefix() {
397+
let (private_key, public_key) = generate_key_pair();
398+
399+
auth::test_auth_succeeds::<JsonResponse, _>(
400+
&AxumTestServer::new_with_auth(public_key, false, mock_prefix_test()).await,
401+
private_key,
402+
)
403+
.await;
404+
}
405+
406+
#[tokio::test]
407+
async fn test_auth_succeeds_regex() {
383408
let (private_key, public_key) = generate_key_pair();
384409

385410
auth::test_auth_succeeds::<JsonResponse, _>(
386-
&AxumTestServer::new_with_auth(public_key, false).await,
411+
&AxumTestServer::new_with_auth(public_key, false, mock_regex_test()).await,
387412
private_key,
388413
)
389414
.await;
@@ -394,7 +419,7 @@ mod tests {
394419
async fn test_auth_insufficient_permissions_suppressed() {
395420
let (private_key, public_key) = generate_key_pair();
396421

397-
let server = AxumTestServer::new_with_auth(public_key, true).await;
422+
let server = AxumTestServer::new_with_auth(public_key, true, mock_id_test()).await;
398423
auth::test_auth_insufficient_permissions::<JsonResponse, _>(&server, private_key).await;
399424
}
400425

@@ -404,7 +429,7 @@ mod tests {
404429
let (private_key, public_key) = generate_key_pair();
405430

406431
auth::test_auth_succeeds::<JsonResponse, _>(
407-
&AxumTestServer::new_with_auth(public_key, true).await,
432+
&AxumTestServer::new_with_auth(public_key, true, mock_id_test()).await,
408433
private_key,
409434
)
410435
.await;

0 commit comments

Comments
 (0)