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 serde_json::json;
|
||||
use tokio::time::Instant;
|
||||
use tower::util::ServiceExt as _;
|
||||
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)]
|
||||
pub(super) async fn handle_ping(
|
||||
@@ -72,7 +71,9 @@ pub(super) async fn default(
|
||||
};
|
||||
|
||||
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!(
|
||||
"authentik_outpost_proxy_request_duration_seconds",
|
||||
|
||||
Reference in New Issue
Block a user