Skip to content

Commit 233d1cf

Browse files
committed
fix(cat-gateway): Add auth to rbac endpoints
1 parent c0a9c83 commit 233d1cf

File tree

7 files changed

+86
-34
lines changed

7 files changed

+86
-34
lines changed

catalyst-gateway/bin/src/service/api/cardano/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ impl CardanoApi {
214214
&self,
215215
/// Stake address to get the chain root for.
216216
Path(stake_address): Path<Cip19StakeAddress>,
217+
/// No Authorization required, but Token permitted.
218+
_auth: NoneOrRBAC,
217219
) -> rbac::chain_root_get::AllResponses {
218220
rbac::chain_root_get::endpoint(stake_address).await
219221
}
@@ -231,6 +233,8 @@ impl CardanoApi {
231233
/// Chain root to get the registrations for.
232234
#[oai(validator(max_length = 66, min_length = 64, pattern = "0x[0-9a-f]{64}"))]
233235
Path(chain_root): Path<String>,
236+
/// No Authorization required, but Token permitted.
237+
_auth: NoneOrRBAC,
234238
) -> rbac::registrations_get::AllResponses {
235239
rbac::registrations_get::endpoint(chain_root).await
236240
}
@@ -248,6 +252,8 @@ impl CardanoApi {
248252
/// Role0 key to get the chain root for.
249253
#[oai(validator(min_length = 34, max_length = 34, pattern = "0x[0-9a-f]{32}"))]
250254
Path(role0_key): Path<String>,
255+
/// No Authorization required, but Token permitted.
256+
_auth: NoneOrRBAC,
251257
) -> rbac::role0_chain_root_get::AllResponses {
252258
rbac::role0_chain_root_get::endpoint(role0_key).await
253259
}

catalyst-gateway/bin/src/service/api/cardano/rbac/chain_root_get.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Implementation of the GET `/rbac/chain_root` endpoint.
2+
use anyhow::anyhow;
23
use der_parser::asn1_rs::ToDer;
34
use futures::StreamExt as _;
45
use poem_openapi::{payload::Json, ApiResponse, Object};
@@ -9,7 +10,10 @@ use crate::{
910
queries::rbac::get_chain_root::{GetChainRootQuery, GetChainRootQueryParams},
1011
session::CassandraSession,
1112
},
12-
service::common::{responses::WithErrorResponses, types::cardano::address::Cip19StakeAddress},
13+
service::common::{
14+
responses::WithErrorResponses,
15+
types::{cardano::address::Cip19StakeAddress, headers::retry_after::RetryAfterOption},
16+
},
1317
};
1418

1519
/// GET RBAC chain root response.
@@ -29,9 +33,6 @@ pub(crate) enum Responses {
2933
/// No chain root found for the given stake address.
3034
#[oai(status = 404)]
3135
NotFound,
32-
/// Internal server error.
33-
#[oai(status = 500)]
34-
InternalServerError,
3536
}
3637

3738
pub(crate) type AllResponses = WithErrorResponses<Responses>;
@@ -40,12 +41,14 @@ pub(crate) type AllResponses = WithErrorResponses<Responses>;
4041
pub(crate) async fn endpoint(stake_address: Cip19StakeAddress) -> AllResponses {
4142
let Some(session) = CassandraSession::get(true) else {
4243
error!("Failed to acquire db session");
43-
return Responses::InternalServerError.into();
44+
let err = anyhow::anyhow!("Failed to acquire db session");
45+
return AllResponses::service_unavailable(&err, RetryAfterOption::Default);
4446
};
4547

4648
let Ok(stake_address) = stake_address.to_der_vec() else {
4749
error!("Failed to create stake address vec");
48-
return Responses::InternalServerError.into();
50+
let err = anyhow!("Failed to create stake address vec");
51+
return AllResponses::internal_error(&err);
4952
};
5053

5154
let query_res =
@@ -58,7 +61,8 @@ pub(crate) async fn endpoint(stake_address: Cip19StakeAddress) -> AllResponses {
5861
Ok(row) => row,
5962
Err(err) => {
6063
error!(error = ?err, "Failed to parse get chain root by stake address query row");
61-
return Responses::InternalServerError.into();
64+
let err = anyhow!(err);
65+
return AllResponses::internal_error(&err);
6266
},
6367
};
6468

@@ -73,7 +77,8 @@ pub(crate) async fn endpoint(stake_address: Cip19StakeAddress) -> AllResponses {
7377
},
7478
Err(err) => {
7579
error!(error = ?err, "Failed to execute get chain root by stake address query");
76-
Responses::InternalServerError.into()
80+
let err = anyhow!(err);
81+
AllResponses::internal_error(&err)
7782
},
7883
}
7984
}

catalyst-gateway/bin/src/service/api/cardano/rbac/registrations_get.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Implementation of the GET `/rbac/registrations` endpoint.
2+
use anyhow::anyhow;
23
use futures::StreamExt as _;
34
use poem_openapi::{payload::Json, ApiResponse, Object};
45
use tracing::error;
@@ -10,7 +11,10 @@ use crate::{
1011
},
1112
session::CassandraSession,
1213
},
13-
service::common::{objects::cardano::hash::Hash, responses::WithErrorResponses},
14+
service::common::{
15+
objects::cardano::hash::Hash, responses::WithErrorResponses,
16+
types::headers::retry_after::RetryAfterOption,
17+
},
1418
};
1519

1620
/// GET RBAC registrations by chain root response list item.
@@ -37,9 +41,6 @@ pub(crate) enum Responses {
3741
/// Response for bad requests.
3842
#[oai(status = 400)]
3943
BadRequest,
40-
/// Internal server error.
41-
#[oai(status = 500)]
42-
InternalServerError,
4344
}
4445

4546
pub(crate) type AllResponses = WithErrorResponses<Responses>;
@@ -48,7 +49,8 @@ pub(crate) type AllResponses = WithErrorResponses<Responses>;
4849
pub(crate) async fn endpoint(chain_root: String) -> AllResponses {
4950
let Some(session) = CassandraSession::get(true) else {
5051
error!("Failed to acquire db session");
51-
return Responses::InternalServerError.into();
52+
let err = anyhow::anyhow!("Failed to acquire db session");
53+
return AllResponses::service_unavailable(&err, RetryAfterOption::Default);
5254
};
5355

5456
let Ok(decoded_chain_root) = hex::decode(chain_root) else {
@@ -70,7 +72,7 @@ pub(crate) async fn endpoint(chain_root: String) -> AllResponses {
7072
error = ?err,
7173
"Failed to execute get registrations by chain root query"
7274
);
73-
return Responses::InternalServerError.into();
75+
return AllResponses::internal_error(&err);
7476
},
7577
};
7678

@@ -80,7 +82,8 @@ pub(crate) async fn endpoint(chain_root: String) -> AllResponses {
8082
Ok(row) => row,
8183
Err(err) => {
8284
error!(error = ?err, "Failed to parse get registrations by chain root query row");
83-
return Responses::InternalServerError.into();
85+
let err = anyhow!(err);
86+
return AllResponses::internal_error(&err);
8487
},
8588
};
8689

catalyst-gateway/bin/src/service/api/cardano/rbac/role0_chain_root_get.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Implementation of the GET `/rbac/role0_chain_root` endpoint.
2+
use anyhow::anyhow;
23
use futures::StreamExt as _;
34
use poem_openapi::{payload::Json, ApiResponse, Object};
45
use tracing::error;
@@ -10,7 +11,9 @@ use crate::{
1011
},
1112
session::CassandraSession,
1213
},
13-
service::common::responses::WithErrorResponses,
14+
service::common::{
15+
responses::WithErrorResponses, types::headers::retry_after::RetryAfterOption,
16+
},
1417
};
1518

1619
/// GET RBAC chain root response.
@@ -33,9 +36,6 @@ pub(crate) enum Responses {
3336
/// Response for bad requests.
3437
#[oai(status = 400)]
3538
BadRequest,
36-
/// Internal server error.
37-
#[oai(status = 500)]
38-
InternalServerError,
3939
}
4040

4141
pub(crate) type AllResponses = WithErrorResponses<Responses>;
@@ -44,7 +44,8 @@ pub(crate) type AllResponses = WithErrorResponses<Responses>;
4444
pub(crate) async fn endpoint(role0_key: String) -> AllResponses {
4545
let Some(session) = CassandraSession::get(true) else {
4646
error!("Failed to acquire db session");
47-
return Responses::InternalServerError.into();
47+
let err = anyhow::anyhow!("Failed to acquire db session");
48+
return AllResponses::service_unavailable(&err, RetryAfterOption::Default);
4849
};
4950

5051
let Ok(decoded_role0_key) = hex::decode(role0_key) else {
@@ -63,7 +64,8 @@ pub(crate) async fn endpoint(role0_key: String) -> AllResponses {
6364
Ok(row) => row,
6465
Err(err) => {
6566
error!(error = ?err, "Failed to parse get chain root by role0 key query row");
66-
return Responses::InternalServerError.into();
67+
let err = anyhow!(err);
68+
return AllResponses::internal_error(&err);
6769
},
6870
};
6971

@@ -78,7 +80,7 @@ pub(crate) async fn endpoint(role0_key: String) -> AllResponses {
7880
},
7981
Err(err) => {
8082
error!(error = ?err, "Failed to execute get chain root by role0 key query");
81-
Responses::InternalServerError.into()
83+
AllResponses::internal_error(&err)
8284
},
8385
}
8486
}

catalyst-gateway/bin/src/service/common/responses/code_503_service_unavailable.rs

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ impl ServiceUnavailable {
2626

2727
Self { id, msg }
2828
}
29+
30+
/// Get the id of this Server Error.
31+
pub(crate) fn id(&self) -> Uuid {
32+
self.id
33+
}
2934
}
3035

3136
impl Example for ServiceUnavailable {

catalyst-gateway/bin/src/service/common/responses/mod.rs

+28-12
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ mod code_503_service_unavailable;
2828
use code_500_internal_server_error::InternalServerError;
2929

3030
use super::types::headers::{
31-
access_control_allow_origin::AccessControlAllowOriginHeader, ratelimit::RateLimitHeader,
32-
retry_after::RetryAfterHeader,
31+
access_control_allow_origin::AccessControlAllowOriginHeader,
32+
ratelimit::RateLimitHeader,
33+
retry_after::{RetryAfterHeader, RetryAfterOption},
3334
};
3435

3536
/// Default error responses
@@ -121,20 +122,35 @@ impl<T> WithErrorResponses<T> {
121122
pub(crate) fn handle_error(err: &anyhow::Error) -> Self {
122123
match err {
123124
err if err.is::<bb8::RunError<tokio_postgres::Error>>() => {
124-
let error = ServiceUnavailable::new(None);
125-
WithErrorResponses::Error(ErrorResponses::ServiceUnavailable(
126-
Json(error),
127-
Some(RetryAfterHeader::default()),
128-
))
129-
},
130-
err => {
131-
let error = InternalServerError::new(None);
132-
error!(id=%error.id(), error=?err);
133-
WithErrorResponses::Error(ErrorResponses::ServerError(Json(error)))
125+
Self::service_unavailable(err, RetryAfterOption::Default)
134126
},
127+
err => Self::internal_error(err),
135128
}
136129
}
137130

131+
/// Handle a 503 service unavailable error response.
132+
///
133+
/// Returns a 503 Service unavailable Error response.
134+
pub(crate) fn service_unavailable(err: &anyhow::Error, retry: RetryAfterOption) -> Self {
135+
let error = ServiceUnavailable::new(None);
136+
error!(id=%error.id(), error=?err, retry_after=?retry);
137+
let retry = match retry {
138+
RetryAfterOption::Default => Some(RetryAfterHeader::default()),
139+
RetryAfterOption::None => None,
140+
RetryAfterOption::Some(value) => Some(value),
141+
};
142+
WithErrorResponses::Error(ErrorResponses::ServiceUnavailable(Json(error), retry))
143+
}
144+
145+
/// Handle a 500 internal error response.
146+
///
147+
/// Returns a 500 Internal Error response.
148+
pub(crate) fn internal_error(err: &anyhow::Error) -> Self {
149+
let error = InternalServerError::new(None);
150+
error!(id=%error.id(), error=?err);
151+
WithErrorResponses::Error(ErrorResponses::ServerError(Json(error)))
152+
}
153+
138154
/// Handle a 401 unauthorized response.
139155
///
140156
/// Returns a 401 Unauthorized response.

catalyst-gateway/bin/src/service/common/types/headers/retry_after.rs

+15
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use poem_openapi::{
1313
use serde_json::Value;
1414

1515
/// Parameter which describes the possible choices for a Retry-After header field.
16+
#[derive(Debug)]
1617
#[allow(dead_code)] // Its OK if all these variants are not used.
1718
pub(crate) enum RetryAfterHeader {
1819
/// Http Date
@@ -21,6 +22,20 @@ pub(crate) enum RetryAfterHeader {
2122
Seconds(u64),
2223
}
2324

25+
/// Parameter which lets us set the retry header, or use some default.
26+
/// Needed, because its valid to exclude the retry header specifically.
27+
/// This is also due to the way Poem handles optional headers.
28+
#[derive(Debug)]
29+
#[allow(dead_code)] // Its OK if all these variants are not used.
30+
pub(crate) enum RetryAfterOption {
31+
/// Use a default Retry After header value
32+
Default,
33+
/// Don't include the Retry After header value in the response.
34+
None,
35+
/// Use a specific Retry After header value
36+
Some(RetryAfterHeader),
37+
}
38+
2439
impl Display for RetryAfterHeader {
2540
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2641
match self {

0 commit comments

Comments
 (0)