use std::{env, sync::Arc, collections::HashMap}; use axum::{ body::Body, extract::{Extension, FromRequest, Query}, http::{request::Parts, Request}, routing::get, Json, Router, response::Redirect, }; use openidconnect::{ core::{CoreClient, CoreProviderMetadata, CoreResponseType}, reqwest::async_http_client, url::Url, AccessTokenHash, AuthenticationFlow, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, OAuth2TokenResponse, PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, }; use protocol::UserInfo; use tower_cookies::{Cookie, CookieManagerLayer, Cookies}; use tower_http::trace::TraceLayer; use tracing::{info, trace}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; mod auth; use crate::auth::Authenticator; struct ServerContext { pub app_url: String, pub authenticator: Authenticator, } type ContextExtension = Extension>; async fn keycloak_client( issuer_url: IssuerUrl, client_id: ClientId, client_secret: ClientSecret, redirect_uri: RedirectUrl, ) -> CoreClient { // // Use OpenID Connect Discovery to fetch the provider metadata. let provider_metadata = CoreProviderMetadata::discover_async(issuer_url, async_http_client) .await .unwrap(); let client = CoreClient::from_provider_metadata(provider_metadata, client_id, Some(client_secret)) // Set the URL the user will be redirected to after the authorization process. .set_redirect_uri(redirect_uri); client } #[tokio::main] async fn main() { dotenv::dotenv().ok(); tracing_subscriber::registry() .with(tracing_subscriber::EnvFilter::new( std::env::var("RUST_LOG").unwrap_or_else(|_| "".into()), )) .with(tracing_subscriber::fmt::layer()) .init(); let bind_address = env::var("BIND_ADDRESS").unwrap(); info!("Starting server on {}", bind_address); let app_url = env::var("APP_URL").unwrap(); let state = Arc::new(ServerContext { app_url: app_url, authenticator: Authenticator::from_env().await, }); let app = Router::new() .route("/api/user/info", get(user_info)) .route("/api/login", get(login)) .route(auth::LOGIN_CALLBACK, get(login_callback)) .layer(CookieManagerLayer::new()) .layer(Extension(state)) .layer(TraceLayer::new_for_http()); axum::Server::bind(&bind_address.parse().unwrap()) .serve(app.into_make_service()) .await .unwrap(); } async fn user_info() -> Json> { Json(None) } async fn login_callback( cookies: Cookies, Query(params): Query>, ) -> () { info!("params: {params:?}"); () } async fn login(cookies: Cookies, extension: ContextExtension) -> Redirect { let (user_id, auth_url) = extension.authenticator.get_login_url().await; trace!("Creating auth url for {user_id:?}"); cookies.add(Cookie::new( "user-id", serde_json::to_string(&user_id).unwrap(), )); Redirect::temporary(auth_url.as_str()) }