mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
start on handlers
Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
This commit is contained in:
@@ -1,61 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use ak_client::models::ProxyOutpostConfig;
|
|
||||||
use ak_common::tls::store::Certificate;
|
|
||||||
use axum::Router;
|
|
||||||
use eyre::{Result, eyre};
|
|
||||||
use tracing::instrument;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::outpost::proxy::ProxyOutpost;
|
|
||||||
|
|
||||||
const _REDIRECT_PARAM: &str = "rd";
|
|
||||||
const CALLBACK_SIGNATURE: &str = "X-authentik-auth-callback";
|
|
||||||
const _LOGOUT_SIGNATURE: &str = "X-authentik-logout";
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(super) struct Application {
|
|
||||||
pub(super) host: String,
|
|
||||||
pub(super) provider: ProxyOutpostConfig,
|
|
||||||
pub(super) router: Router,
|
|
||||||
pub(super) cert: Option<Arc<Certificate>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Application {
|
|
||||||
#[instrument(skip_all)]
|
|
||||||
pub(super) async fn new(outpost: &ProxyOutpost, provider: ProxyOutpostConfig) -> Result<Self> {
|
|
||||||
let external_url = Url::parse(&provider.external_host)?;
|
|
||||||
if !external_url.has_authority() {
|
|
||||||
return Err(eyre!("no host in external host"));
|
|
||||||
}
|
|
||||||
let external_host = external_url.authority();
|
|
||||||
|
|
||||||
let _old_app = outpost.apps.load().get(external_host);
|
|
||||||
|
|
||||||
let cert = if let Some(Some(kp_uuid)) = provider.certificate {
|
|
||||||
Some(
|
|
||||||
outpost
|
|
||||||
.certificate_store
|
|
||||||
.ensure_keypair(&outpost.controller.api_config, kp_uuid)
|
|
||||||
.await?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let _redirect_url = {
|
|
||||||
let mut redirect_url = external_url.join("outpost.goauthentik.io/callback")?;
|
|
||||||
redirect_url.set_query(Some(&format!("{CALLBACK_SIGNATURE}=true")));
|
|
||||||
redirect_url
|
|
||||||
};
|
|
||||||
|
|
||||||
let router = Router::new();
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
host: external_host.to_owned(),
|
|
||||||
provider,
|
|
||||||
router,
|
|
||||||
cert,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ak_axum::error::Result;
|
||||||
|
use axum::{
|
||||||
|
extract::{Request, State},
|
||||||
|
response::Response,
|
||||||
|
};
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
|
use crate::outpost::proxy::application::Application;
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(crate) async fn handle_caddy(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(crate) async fn handle_envoy(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(crate) async fn handle_nginx(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(crate) async fn handle_traefik(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
|
use ak_axum::error::Result;
|
||||||
|
use axum::{
|
||||||
|
extract::{Query, Request, State},
|
||||||
|
response::Response,
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use tower::util::ServiceExt as _;
|
||||||
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
|
use crate::outpost::proxy::application::Application;
|
||||||
|
|
||||||
|
pub(super) mod forward;
|
||||||
|
pub(super) mod proxy;
|
||||||
|
|
||||||
|
// TODO: move this to ak-common
|
||||||
|
fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
T: FromStr,
|
||||||
|
T::Err: fmt::Display,
|
||||||
|
{
|
||||||
|
let opt = Option::<String>::deserialize(de)?;
|
||||||
|
match opt.as_deref() {
|
||||||
|
None | Some("") => Ok(None),
|
||||||
|
Some(s) => FromStr::from_str(s)
|
||||||
|
.map_err(serde::de::Error::custom)
|
||||||
|
.map(Some),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Parameters {
|
||||||
|
// #[serde(rename = "rd", default, deserialize_with = "empty_string_as_none")]
|
||||||
|
// redirect: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename = "X-authentik-auth-callback",
|
||||||
|
default,
|
||||||
|
deserialize_with = "empty_string_as_none"
|
||||||
|
)]
|
||||||
|
callback_signature: Option<bool>,
|
||||||
|
#[serde(
|
||||||
|
rename = "X-authentik-logout",
|
||||||
|
default,
|
||||||
|
deserialize_with = "empty_string_as_none"
|
||||||
|
)]
|
||||||
|
logout_signature: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(crate) async fn handle(app: Arc<Application>, request: Request) -> Result<Response> {
|
||||||
|
if let Ok(query) = Query::<Parameters>::try_from_uri(request.uri()) {
|
||||||
|
if query.callback_signature == Some(true) {
|
||||||
|
debug!("handling OAuth Callback from querystring signature");
|
||||||
|
return handle_auth_callback(State(app), request).await;
|
||||||
|
}
|
||||||
|
if query.logout_signature == Some(true) {
|
||||||
|
debug!("handling OAuth Logout from querystring signature");
|
||||||
|
return handle_sign_out(State(app), request).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(app.router.clone().with_state(app).oneshot(request).await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(super) async fn handle_auth_callback(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(super) async fn handle_sign_out(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ak_axum::error::Result;
|
||||||
|
use axum::{
|
||||||
|
extract::{Request, State},
|
||||||
|
response::Response,
|
||||||
|
};
|
||||||
|
use tracing::instrument;
|
||||||
|
|
||||||
|
use crate::outpost::proxy::application::Application;
|
||||||
|
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(crate) async fn handle(
|
||||||
|
State(_app): State<Arc<Application>>,
|
||||||
|
_request: Request,
|
||||||
|
) -> Result<Response> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use ak_client::models::{ProxyMode, ProxyOutpostConfig};
|
||||||
|
use ak_common::tls::store::Certificate;
|
||||||
|
use axum::{Router, routing::any};
|
||||||
|
use eyre::{Result, eyre};
|
||||||
|
use tracing::instrument;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::outpost::proxy::ProxyOutpost;
|
||||||
|
|
||||||
|
pub(super) mod handlers;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct Application {
|
||||||
|
pub(super) host: String,
|
||||||
|
pub(super) provider: ProxyOutpostConfig,
|
||||||
|
pub(super) router: Router<Arc<Self>>,
|
||||||
|
pub(super) cert: Option<Arc<Certificate>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Application {
|
||||||
|
#[instrument(skip_all)]
|
||||||
|
pub(super) async fn new(outpost: &ProxyOutpost, provider: ProxyOutpostConfig) -> Result<Self> {
|
||||||
|
let external_url = Url::parse(&provider.external_host)?;
|
||||||
|
if !external_url.has_authority() {
|
||||||
|
return Err(eyre!("no host in external host"));
|
||||||
|
}
|
||||||
|
let external_host = external_url.authority();
|
||||||
|
|
||||||
|
let _old_app = outpost.apps.load().get(external_host);
|
||||||
|
|
||||||
|
let cert = if let Some(Some(kp_uuid)) = provider.certificate {
|
||||||
|
Some(
|
||||||
|
outpost
|
||||||
|
.certificate_store
|
||||||
|
.ensure_keypair(&outpost.controller.api_config, kp_uuid)
|
||||||
|
.await?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let router = Router::new()
|
||||||
|
// TODO: /start
|
||||||
|
.route(
|
||||||
|
"/outpost.goauthentik.io/callback",
|
||||||
|
any(handlers::handle_auth_callback),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/outpost.goauthentik.io/sign_out",
|
||||||
|
any(handlers::handle_sign_out),
|
||||||
|
);
|
||||||
|
|
||||||
|
let router = match provider.mode {
|
||||||
|
Some(ProxyMode::ForwardSingle | ProxyMode::ForwardDomain) => router
|
||||||
|
.route(
|
||||||
|
"/outpost.goauthentik.io/auth/caddy",
|
||||||
|
any(handlers::forward::handle_caddy),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/outpost.goauthentik.io/auth/envoy",
|
||||||
|
any(handlers::forward::handle_envoy),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/outpost.goauthentik.io/auth/nginx",
|
||||||
|
any(handlers::forward::handle_nginx),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/outpost.goauthentik.io/auth/traefik",
|
||||||
|
any(handlers::forward::handle_traefik),
|
||||||
|
),
|
||||||
|
Some(ProxyMode::Proxy) => router.fallback(handlers::proxy::handle),
|
||||||
|
None => return Err(eyre!("no provider mode set")),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
host: external_host.to_owned(),
|
||||||
|
provider,
|
||||||
|
router,
|
||||||
|
cert,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,10 +9,9 @@ use axum::{
|
|||||||
use metrics::histogram;
|
use metrics::histogram;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::time::Instant;
|
use tokio::time::Instant;
|
||||||
use tower::util::ServiceExt as _;
|
|
||||||
use tracing::{Instrument as _, debug, field, info_span, instrument, trace, warn};
|
use tracing::{Instrument as _, debug, field, info_span, instrument, trace, warn};
|
||||||
|
|
||||||
use crate::outpost::proxy::ProxyOutpost;
|
use crate::outpost::proxy::{ProxyOutpost, application};
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub(super) async fn handle_ping(
|
pub(super) async fn handle_ping(
|
||||||
@@ -72,7 +71,9 @@ pub(super) async fn default(
|
|||||||
};
|
};
|
||||||
|
|
||||||
trace!("passing to application");
|
trace!("passing to application");
|
||||||
let response = app.router.clone().oneshot(request).instrument(span).await?;
|
let response = application::handlers::handle(app, request)
|
||||||
|
.instrument(span)
|
||||||
|
.await?;
|
||||||
|
|
||||||
histogram!(
|
histogram!(
|
||||||
"authentik_outpost_proxy_request_duration_seconds",
|
"authentik_outpost_proxy_request_duration_seconds",
|
||||||
|
|||||||
Reference in New Issue
Block a user