Skip to content

Commit 6f58587

Browse files
committed
setup a basic middleware
1 parent 95c37c7 commit 6f58587

3 files changed

Lines changed: 120 additions & 0 deletions

File tree

src/webserver/http.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use actix_web::{
2020
use actix_web::{HttpResponseBuilder, ResponseError};
2121

2222
use super::https::make_auto_rustls_config;
23+
use super::oidc::OidcMiddleware;
2324
use super::response_writer::ResponseWriter;
2425
use super::static_content;
2526
use crate::webserver::routing::RoutingAction::{
@@ -466,6 +467,7 @@ pub fn create_app(
466467
)
467468
// when receiving a request outside of the prefix, redirect to the prefix
468469
.default_service(fn_service(default_prefix_redirect))
470+
.wrap(OidcMiddleware::new(&app_state.config))
469471
.wrap(Logger::default())
470472
.wrap(default_headers(&app_state))
471473
.wrap(middleware::Condition::new(

src/webserver/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ pub use database::migrations::apply;
4545
pub mod response_writer;
4646
pub mod routing;
4747
mod static_content;
48+
mod oidc;

src/webserver/oidc.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use std::{
2+
future::{ready, Future, Ready},
3+
pin::Pin,
4+
sync::Arc,
5+
};
6+
7+
use crate::app_config::AppConfig;
8+
use actix_web::{
9+
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
10+
middleware::Condition,
11+
Error,
12+
};
13+
14+
#[derive(Clone, Debug)]
15+
pub struct OidcConfig {
16+
pub issuer_url: String,
17+
pub client_id: String,
18+
pub client_secret: String,
19+
pub scopes: String,
20+
}
21+
22+
impl TryFrom<&AppConfig> for OidcConfig {
23+
type Error = Option<&'static str>;
24+
25+
fn try_from(config: &AppConfig) -> Result<Self, Self::Error> {
26+
let issuer_url = config.oidc_issuer_url.as_ref().ok_or(None)?;
27+
let client_secret = config
28+
.oidc_client_secret
29+
.as_ref()
30+
.ok_or(Some("Missing oidc_client_secret"))?;
31+
32+
Ok(Self {
33+
issuer_url: issuer_url.clone(),
34+
client_id: config.oidc_client_id.clone(),
35+
client_secret: client_secret.clone(),
36+
scopes: config.oidc_scopes.clone(),
37+
})
38+
}
39+
}
40+
41+
pub struct OidcMiddleware {
42+
pub config: Option<Arc<OidcConfig>>,
43+
}
44+
45+
impl OidcMiddleware {
46+
pub fn new(config: &AppConfig) -> Condition<Self> {
47+
let config = OidcConfig::try_from(config);
48+
match &config {
49+
Ok(config) => {
50+
log::info!("Setting up OIDC with config: {config:?}");
51+
}
52+
Err(Some(err)) => {
53+
log::error!("Invalid OIDC configuration: {err}");
54+
}
55+
Err(None) => {
56+
log::debug!("No OIDC configuration provided, skipping middleware.");
57+
}
58+
}
59+
let config = config.ok().map(Arc::new);
60+
Condition::new(config.is_some(), Self { config })
61+
}
62+
}
63+
64+
impl<S, B> Transform<S, ServiceRequest> for OidcMiddleware
65+
where
66+
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
67+
S::Future: 'static,
68+
B: 'static,
69+
{
70+
type Response = ServiceResponse<B>;
71+
type Error = Error;
72+
type InitError = ();
73+
type Transform = OidcService<S>;
74+
type Future = Ready<Result<Self::Transform, Self::InitError>>;
75+
76+
fn new_transform(&self, service: S) -> Self::Future {
77+
ready(
78+
self.config
79+
.as_ref()
80+
.map(|config| OidcService {
81+
service,
82+
config: Arc::clone(config),
83+
})
84+
.ok_or(()),
85+
)
86+
}
87+
}
88+
89+
pub struct OidcService<S> {
90+
service: S,
91+
config: Arc<OidcConfig>,
92+
}
93+
94+
type LocalBoxFuture<T> = Pin<Box<dyn Future<Output = T> + 'static>>;
95+
96+
impl<S, B> Service<ServiceRequest> for OidcService<S>
97+
where
98+
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
99+
S::Future: 'static,
100+
B: 'static,
101+
{
102+
type Response = ServiceResponse<B>;
103+
type Error = Error;
104+
type Future = LocalBoxFuture<Result<Self::Response, Self::Error>>;
105+
106+
forward_ready!(service);
107+
108+
fn call(&self, request: ServiceRequest) -> Self::Future {
109+
log::info!("OIDC config: {:?}", self.config);
110+
let future = self.service.call(request);
111+
112+
Box::pin(async move {
113+
let response = future.await?;
114+
Ok(response)
115+
})
116+
}
117+
}

0 commit comments

Comments
 (0)