diff options
Diffstat (limited to 'server-old')
-rw-r--r-- | server-old/.env | 3 | ||||
-rw-r--r-- | server-old/Cargo.toml | 16 | ||||
-rw-r--r-- | server-old/Rocket.toml | 4 | ||||
-rw-r--r-- | server-old/src/main.rs | 168 |
4 files changed, 191 insertions, 0 deletions
diff --git a/server-old/.env b/server-old/.env new file mode 100644 index 0000000..14d8663 --- /dev/null +++ b/server-old/.env @@ -0,0 +1,3 @@ +RUST_LOG=info +ROCKET_PROFILE=development +WEBAPP_PATH=../webapp/dist/
\ No newline at end of file diff --git a/server-old/Cargo.toml b/server-old/Cargo.toml new file mode 100644 index 0000000..7d7011b --- /dev/null +++ b/server-old/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "server" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.65" +dotenv = "0.15.0" +log = "0.4.17" +env_logger = "0.8.4" +openidconnect = "2.3.2" +rocket = { version = "0.5.0-rc.2", features = ["secrets", "json"] } +jwt-simple = "0.11.0" +serde = { version = "1.0.145", features = ["derive"] } +chrono = { version = "0.4.22", features = ["serde"] } +serde_json = "1.0.85" diff --git a/server-old/Rocket.toml b/server-old/Rocket.toml new file mode 100644 index 0000000..c7c73fa --- /dev/null +++ b/server-old/Rocket.toml @@ -0,0 +1,4 @@ +[development] +address = "::" +port = 11120 +secret_key = "1SmYoERqnfzf8dhTNEMp1VYrK7UCYhCbijQtSaF5LOI=" diff --git a/server-old/src/main.rs b/server-old/src/main.rs new file mode 100644 index 0000000..411ea47 --- /dev/null +++ b/server-old/src/main.rs @@ -0,0 +1,168 @@ +#[macro_use] +extern crate rocket; + +use chrono::{DateTime, Utc}; +use rocket::fs::FileServer; +use rocket::http::uri::Reference; +use rocket::http::{Cookie, CookieJar, Status}; +use rocket::outcome::Outcome; +use rocket::request::{self, FromRequest}; +use rocket::response::{Redirect, content}; +use rocket::Request; +use serde::{Deserialize, Serialize}; +use std::result::Result; +use rocket::serde::json::Json; + +use openidconnect::core::{ + CoreAuthenticationFlow, CoreClient, CoreProviderMetadata, CoreResponseType, CoreUserInfoClaims, +}; +use openidconnect::reqwest::async_http_client; +use openidconnect::url::Url; +use openidconnect::{ + AccessTokenHash, AuthenticationFlow, AuthorizationCode, ClientId, ClientSecret, CsrfToken, + IssuerUrl, Nonce, OAuth2TokenResponse, PkceCodeChallenge, RedirectUrl, Scope, TokenResponse, +}; + +const USER_COOKIE: &'static str = "user"; + +#[derive(Serialize, Deserialize)] +struct UserCookie { + access_token: openidconnect::AccessToken, + expiration: DateTime<Utc>, + refresh_token: openidconnect::RefreshToken, +} + +struct User {} + +impl User { + async fn from_request_helper(req: &Request<'_>) -> Result<User, anyhow::Error> { + let cookie = req + .cookies() + .get_private(USER_COOKIE) + .ok_or(anyhow::anyhow!("no cookie"))?; + let user_cookie: UserCookie = serde_json::from_str(cookie.value())?; + let client = keycloak_client().await; + + let token = client + .exchange_refresh_token(&user_cookie.refresh_token) + .request_async(async_http_client) + .await?; + let user_info: CoreUserInfoClaims = client + .user_info(token.access_token().clone(), None)? + .request_async(async_http_client) + .await?; + log::info!("Got user_info: {:?}", user_info); + Ok(User {}) + } +} + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for User { + type Error = anyhow::Error; + + async fn from_request(req: &'r Request<'_>) -> request::Outcome<Self, Self::Error> { + match User::from_request_helper(req).await { + Ok(user) => Outcome::Success(User {}), + Err(error) => Outcome::Failure((Status::Forbidden, error)), + } + } +} + +#[get("/")] +fn index(user: Option<User>) -> String { + match user { + None => "Not logged in".to_string(), + Some(user) => "Logged in".to_string(), + } +} + +#[get("/test")] +fn test() -> Json<String> { + Json(String::from("test")) +} + +async fn keycloak_client() -> CoreClient { + // // Use OpenID Connect Discovery to fetch the provider metadata. + let provider_metadata = CoreProviderMetadata::discover_async( + IssuerUrl::new("https://auth.orbekk.com/realms/test".to_string()).unwrap(), + async_http_client, + ) + .await + .unwrap(); + + let client = CoreClient::from_provider_metadata( + provider_metadata, + ClientId::new("test-client".to_string()), + Some(ClientSecret::new( + "EbIMIpGnYPrG1GBl6eZtVM5zIhiuu5p1".to_string(), + )), + ) + // Set the URL the user will be redirected to after the authorization process. + .set_redirect_uri( + RedirectUrl::new("https://bridge.orbekk.com/keycloak-callback".to_string()).unwrap(), + ); + + client +} + +#[get("/login")] +async fn login() -> Redirect { + let (auth_url, csrf_token, nonce) = keycloak_client() + .await + .authorize_url( + AuthenticationFlow::<CoreResponseType>::AuthorizationCode, + CsrfToken::new_random, + Nonce::new_random, + ) + .add_scope(Scope::new("email".to_string())) + .add_scope(Scope::new("profile".to_string())) + .url(); + + log::info!("{:?}", auth_url); + Redirect::to(Reference::parse_owned(auth_url.into()).unwrap()) +} + +#[get("/keycloak-callback?<code>&<state>")] +async fn keycloak_callback(jar: &CookieJar<'_>, code: &str, state: &str) -> Redirect { + // TODO: Validate state + let request_time = Utc::now(); + let token = keycloak_client() + .await + .exchange_code(AuthorizationCode::new(code.to_string())) + .request_async(async_http_client) + .await + .unwrap(); + + log::info!("token: {:?}", token); + log::info!("access token {:?}", token.access_token().secret()); + log::info!( + "refresh token {:?}", + token.refresh_token().unwrap().secret() + ); + let expiration = + request_time + chrono::Duration::from_std(token.expires_in().unwrap()).unwrap(); + jar.add_private(Cookie::new( + USER_COOKIE, + serde_json::to_string(&UserCookie { + access_token: token.access_token().clone(), + expiration, + refresh_token: token.refresh_token().unwrap().clone(), + }) + .unwrap(), + )); + + Redirect::to(uri!(index)) +} + +#[rocket::main] +async fn main() -> Result<(), anyhow::Error> { + dotenv::dotenv().ok(); + env_logger::init(); + + rocket::build() + .mount("/api", routes![index, test, login, keycloak_callback]) + .mount("/", FileServer::from(std::env::var("WEBAPP_PATH").unwrap())) + .launch() + .await?; + Ok(()) +} |