Redirect user to authentication
This commit is contained in:
@ -100,33 +100,29 @@ impl AppConfig {
|
||||
}
|
||||
|
||||
/// Get Redis connection configuration
|
||||
pub fn redis_connection_config(&self) -> redis::ConnectionInfo {
|
||||
redis::ConnectionInfo {
|
||||
addr: redis::ConnectionAddr::Tcp(self.redis_hostname.clone(), self.redis_port),
|
||||
redis: redis::RedisConnectionInfo {
|
||||
db: self.redis_db_number,
|
||||
username: self.redis_username.clone(),
|
||||
password: Some(self.redis_password.clone()),
|
||||
protocol: Default::default(),
|
||||
},
|
||||
}
|
||||
pub fn redis_connection_string(&self) -> String {
|
||||
format!(
|
||||
"redis://{}:{}@{}:{}/{}",
|
||||
self.redis_username.as_deref().unwrap_or(""),
|
||||
self.redis_password,
|
||||
self.redis_hostname,
|
||||
self.redis_port,
|
||||
self.redis_db_number
|
||||
)
|
||||
}
|
||||
|
||||
/// Get OpenID providers configuration
|
||||
pub fn openid_providers(&self) -> OIDCProvider<'_> {
|
||||
pub fn openid_provider(&self) -> OIDCProvider<'_> {
|
||||
OIDCProvider {
|
||||
client_id: self.oidc_client_id.as_str(),
|
||||
client_secret: self.oidc_client_secret.as_str(),
|
||||
configuration_url: self.oidc_configuration_url.as_str(),
|
||||
redirect_url: self
|
||||
.oidc_redirect_url
|
||||
.replace("APP_ORIGIN", &self.website_origin),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get OIDC callback URL
|
||||
pub fn oidc_redirect_url(&self) -> String {
|
||||
self.oidc_redirect_url
|
||||
.replace("APP_ORIGIN", &self.website_origin)
|
||||
}
|
||||
|
||||
/// Get s3 bucket credentials
|
||||
pub fn s3_credentials(&self) -> anyhow::Result<Credentials> {
|
||||
Ok(Credentials::new(
|
||||
@ -157,4 +153,5 @@ pub struct OIDCProvider<'a> {
|
||||
pub client_id: &'a str,
|
||||
pub client_secret: &'a str,
|
||||
pub configuration_url: &'a str,
|
||||
pub redirect_url: String,
|
||||
}
|
||||
|
5
src/constants.rs
Normal file
5
src/constants.rs
Normal file
@ -0,0 +1,5 @@
|
||||
/// Session key for OpenID login state
|
||||
pub const STATE_KEY: &str = "oidc-state";
|
||||
|
||||
/// Session key for user information
|
||||
pub const USER_SESSION_KEY: &str = "user";
|
@ -1 +1,5 @@
|
||||
pub mod app_config;
|
||||
pub mod constants;
|
||||
pub mod server;
|
||||
pub mod user;
|
||||
pub mod utils;
|
||||
|
25
src/main.rs
25
src/main.rs
@ -1,23 +1,34 @@
|
||||
use actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};
|
||||
use actix_session::{storage::RedisSessionStore, SessionMiddleware};
|
||||
use actix_web::cookie::Key;
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use matrix_gateway::app_config::AppConfig;
|
||||
|
||||
async fn home() -> HttpResponse {
|
||||
HttpResponse::Ok().body("Hey there!")
|
||||
}
|
||||
use matrix_gateway::server::web_ui;
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
|
||||
// FIXME : not scalable
|
||||
let secret_key = Key::generate();
|
||||
|
||||
let redis_store = RedisSessionStore::new(AppConfig::get().redis_connection_string())
|
||||
.await
|
||||
.expect("Failed to connect to Redis!");
|
||||
|
||||
log::info!(
|
||||
"Starting to listen on {} for {}",
|
||||
AppConfig::get().listen_address,
|
||||
AppConfig::get().website_origin
|
||||
);
|
||||
HttpServer::new(|| {
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
// Add session management to your application using Redis for session state storage
|
||||
.wrap(SessionMiddleware::new(
|
||||
redis_store.clone(),
|
||||
secret_key.clone(),
|
||||
))
|
||||
// Web configuration routes
|
||||
.route("/", web::get().to(home))
|
||||
.route("/", web::get().to(web_ui::home))
|
||||
|
||||
// API routes
|
||||
// TODO
|
||||
|
37
src/server/mod.rs
Normal file
37
src/server/mod.rs
Normal file
@ -0,0 +1,37 @@
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{HttpResponse, ResponseError};
|
||||
use std::error::Error;
|
||||
|
||||
pub mod web_ui;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum HttpFailure {
|
||||
#[error("this resource requires higher privileges")]
|
||||
Forbidden,
|
||||
#[error("this resource was not found")]
|
||||
NotFound,
|
||||
#[error("an unhandled session insert error occurred")]
|
||||
SessionInsertError(#[from] actix_session::SessionInsertError),
|
||||
#[error("an unhandled session error occurred")]
|
||||
SessionError(#[from] actix_session::SessionGetError),
|
||||
#[error("an unspecified open id error occurred: {0}")]
|
||||
OpenID(Box<dyn Error>),
|
||||
#[error("an unspecified internal error occurred: {0}")]
|
||||
InternalError(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
impl ResponseError for HttpFailure {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match &self {
|
||||
Self::Forbidden => StatusCode::FORBIDDEN,
|
||||
Self::NotFound => StatusCode::NOT_FOUND,
|
||||
_ => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::build(self.status_code()).body(self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub type HttpResult = std::result::Result<HttpResponse, HttpFailure>;
|
30
src/server/web_ui.rs
Normal file
30
src/server/web_ui.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::app_config::AppConfig;
|
||||
use crate::constants::{STATE_KEY, USER_SESSION_KEY};
|
||||
use crate::server::{HttpFailure, HttpResult};
|
||||
use crate::user::User;
|
||||
use crate::utils;
|
||||
use actix_session::Session;
|
||||
use actix_web::HttpResponse;
|
||||
use light_openid::primitives::OpenIDConfig;
|
||||
|
||||
pub async fn home(session: Session) -> HttpResult {
|
||||
// Get user information
|
||||
let Some(user): Option<User> = session.get(USER_SESSION_KEY)? else {
|
||||
// Generate auth state
|
||||
let state = utils::rand_str(10);
|
||||
session.insert(STATE_KEY, &state)?;
|
||||
|
||||
let oidc = AppConfig::get().openid_provider();
|
||||
let config = OpenIDConfig::load_from_url(oidc.configuration_url)
|
||||
.await
|
||||
.map_err(HttpFailure::OpenID)?;
|
||||
|
||||
let auth_url = config.gen_authorization_url(oidc.client_id, &state, &oidc.redirect_url);
|
||||
|
||||
return Ok(HttpResponse::Found()
|
||||
.append_header(("location", auth_url))
|
||||
.finish());
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().body("You are authenticated!"))
|
||||
}
|
9
src/user.rs
Normal file
9
src/user.rs
Normal file
@ -0,0 +1,9 @@
|
||||
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct UserID(String);
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct User {
|
||||
pub id: UserID,
|
||||
pub name: String,
|
||||
pub email: String,
|
||||
}
|
6
src/utils.rs
Normal file
6
src/utils.rs
Normal file
@ -0,0 +1,6 @@
|
||||
use rand::distr::{Alphanumeric, SampleString};
|
||||
|
||||
// Generate a random string of a given size
|
||||
pub fn rand_str(len: usize) -> String {
|
||||
Alphanumeric.sample_string(&mut rand::rng(), len)
|
||||
}
|
Reference in New Issue
Block a user