Compare commits
No commits in common. "70aaa1ff44a66501c27adbe73da7321050515d3e" and "d75242d21394cb764a83ea7a56c29fbbd57bf747" have entirely different histories.
70aaa1ff44
...
d75242d213
1926
Cargo.lock
generated
1926
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -6,8 +6,8 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "3.1.6", features = ["derive", "env"] }
|
rocket = "0.5.0-rc.1"
|
||||||
actix-web = "4"
|
rocket_dyn_templates = { version = "0.1.0-rc.1", features = ["tera"] }
|
||||||
include_dir = "0.7.2"
|
include_dir = "0.7.2"
|
||||||
log = "0.4.16"
|
log = "0.4.16"
|
||||||
serde_json = "1.0.79"
|
serde_json = "1.0.79"
|
||||||
@ -15,5 +15,3 @@ env_logger = "0.9.0"
|
|||||||
serde = { version = "1.0.136", features = ["derive"] }
|
serde = { version = "1.0.136", features = ["derive"] }
|
||||||
bcrypt = "0.12.1"
|
bcrypt = "0.12.1"
|
||||||
uuid = { version = "0.8.2", features = ["v4"] }
|
uuid = { version = "0.8.2", features = ["v4"] }
|
||||||
mime_guess = "2.0.4"
|
|
||||||
askama = "0.11.1"
|
|
@ -1,57 +0,0 @@
|
|||||||
html,
|
|
||||||
body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding-top: 40px;
|
|
||||||
padding-bottom: 40px;
|
|
||||||
/* background-color: #f5f5f5; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 330px;
|
|
||||||
padding: 15px;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin .checkbox {
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-signin .form-floating:focus-within {
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-floating:first-child input {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-floating:not(:first-child):not(:last-child) input {
|
|
||||||
margin-bottom: -1px;
|
|
||||||
border-bottom-right-radius: 0;
|
|
||||||
border-bottom-left-radius: 0;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-floating:last-child input {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control {
|
|
||||||
background-color: var(--bs-gray-700);
|
|
||||||
color: var(--bs-gray-100);
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:focus {
|
|
||||||
background-color: var(--bs-gray-600);
|
|
||||||
color: var(--bs-gray-100);
|
|
||||||
}
|
|
5
assets/css/login.css
Normal file
5
assets/css/login.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Login page
|
||||||
|
*
|
||||||
|
* @author Pierre Hubert
|
||||||
|
*/
|
@ -1,5 +0,0 @@
|
|||||||
// Remove un-used alerts
|
|
||||||
document.querySelectorAll("[role=alert]").forEach(el => {
|
|
||||||
if(el.innerHTML.trim() === "")
|
|
||||||
el.remove();
|
|
||||||
})
|
|
@ -4,6 +4,3 @@ pub const USERS_LIST_FILE: &str = "users.json";
|
|||||||
/// Default built-in credentials
|
/// Default built-in credentials
|
||||||
pub const DEFAULT_ADMIN_USERNAME: &str = "admin";
|
pub const DEFAULT_ADMIN_USERNAME: &str = "admin";
|
||||||
pub const DEFAULT_ADMIN_PASSWORD: &str = "admin";
|
pub const DEFAULT_ADMIN_PASSWORD: &str = "admin";
|
||||||
|
|
||||||
/// App name
|
|
||||||
pub const APP_NAME: &str = "Basic OIDC";
|
|
@ -1,20 +1,22 @@
|
|||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use actix_web::{HttpResponse, web};
|
|
||||||
use include_dir::{Dir, include_dir};
|
use include_dir::{Dir, include_dir};
|
||||||
|
use rocket::http::{ContentType, Status};
|
||||||
|
|
||||||
/// Assets directory
|
/// Assets directory
|
||||||
static ASSETS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/assets");
|
static ASSETS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/assets");
|
||||||
|
|
||||||
pub async fn assets_route(path: web::Path<String>) -> HttpResponse {
|
#[get("/<file..>")]
|
||||||
let path: &Path = path.as_ref().as_ref();
|
pub fn assets_route(file: PathBuf) -> (Status, (ContentType, &'static [u8])) {
|
||||||
match ASSETS_DIR.get_file(path) {
|
match ASSETS_DIR.get_file(file) {
|
||||||
None => HttpResponse::NotFound().body("404 Not found"),
|
None =>
|
||||||
|
(Status::NotFound, (ContentType::Text, "404 Not found".as_bytes())),
|
||||||
Some(file) => {
|
Some(file) => {
|
||||||
let res = mime_guess::from_path(path).first_or_octet_stream();
|
(Status::Ok, (
|
||||||
HttpResponse::Ok()
|
ContentType::from_extension(file.path().extension().unwrap_or_default()
|
||||||
.content_type(res.to_string())
|
.to_string_lossy().as_ref())
|
||||||
.body(file.contents())
|
.unwrap_or(ContentType::Binary),
|
||||||
|
file.contents()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,35 +0,0 @@
|
|||||||
use actix_web::{HttpResponse, Responder};
|
|
||||||
use askama::Template;
|
|
||||||
|
|
||||||
use crate::constants::APP_NAME;
|
|
||||||
|
|
||||||
#[derive(Template)]
|
|
||||||
#[template(path = "base_login_page.html")]
|
|
||||||
struct BaseLoginPage {
|
|
||||||
danger: String,
|
|
||||||
success: String,
|
|
||||||
page_title: &'static str,
|
|
||||||
app_name: &'static str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Template)]
|
|
||||||
#[template(path = "login.html")]
|
|
||||||
struct LoginTemplate {
|
|
||||||
_parent: BaseLoginPage,
|
|
||||||
mail: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub async fn login_route() -> impl Responder {
|
|
||||||
HttpResponse::Ok()
|
|
||||||
.content_type("text/html")
|
|
||||||
.body(LoginTemplate {
|
|
||||||
_parent: BaseLoginPage {
|
|
||||||
page_title: "Login",
|
|
||||||
danger: "".to_string(),
|
|
||||||
success: "".to_string(),
|
|
||||||
app_name: APP_NAME,
|
|
||||||
},
|
|
||||||
mail: "".to_string()
|
|
||||||
}.render().unwrap())
|
|
||||||
}
|
|
@ -1,2 +1 @@
|
|||||||
pub mod assets_controller;
|
pub mod assets_controller;
|
||||||
pub mod login_controller;
|
|
@ -1,20 +1,11 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use rocket::serde::Deserialize;
|
||||||
use clap::Parser;
|
|
||||||
|
|
||||||
use crate::constants::USERS_LIST_FILE;
|
use crate::constants::USERS_LIST_FILE;
|
||||||
|
|
||||||
/// Basic OIDC provider
|
#[derive(Debug, Deserialize)]
|
||||||
#[derive(Parser, Debug)]
|
#[serde(crate = "rocket::serde")]
|
||||||
#[clap(author, version, about, long_about = None)]
|
|
||||||
pub struct AppConfig {
|
pub struct AppConfig {
|
||||||
/// Listen address
|
storage_path: PathBuf,
|
||||||
#[clap(short, long, env, default_value = "0.0.0.0:8000")]
|
|
||||||
pub listen_address: String,
|
|
||||||
|
|
||||||
/// Storage path
|
|
||||||
#[clap(short, long, env)]
|
|
||||||
pub storage_path: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppConfig {
|
impl AppConfig {
|
||||||
@ -23,6 +14,6 @@ impl AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn users_file(&self) -> PathBuf {
|
pub fn users_file(&self) -> PathBuf {
|
||||||
self.storage_path().join(USERS_LIST_FILE)
|
self.storage_path.join(USERS_LIST_FILE)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,7 @@ pub struct EntityManager<E> {
|
|||||||
list: Vec<E>,
|
list: Vec<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> EntityManager<E> where E: serde::Serialize + serde::de::DeserializeOwned + Eq + Clone {
|
impl<E> EntityManager<E> where E: rocket::serde::Serialize + rocket::serde::DeserializeOwned + Eq + Clone {
|
||||||
/// Open entity
|
/// Open entity
|
||||||
pub fn open_or_create<A: AsRef<Path>>(path: A) -> Res<Self> {
|
pub fn open_or_create<A: AsRef<Path>>(path: A) -> Res<Self> {
|
||||||
if !path.as_ref().is_file() {
|
if !path.as_ref().is_file() {
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
|
||||||
pub mod data;
|
pub mod data;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
40
src/main.rs
40
src/main.rs
@ -1,24 +1,31 @@
|
|||||||
use actix_web::{App, get, HttpServer, web};
|
#[macro_use]
|
||||||
use actix_web::middleware::Logger;
|
extern crate rocket;
|
||||||
use clap::Parser;
|
|
||||||
|
use rocket::fairing::AdHoc;
|
||||||
|
|
||||||
use basic_oidc::constants::{DEFAULT_ADMIN_PASSWORD, DEFAULT_ADMIN_USERNAME};
|
use basic_oidc::constants::{DEFAULT_ADMIN_PASSWORD, DEFAULT_ADMIN_USERNAME};
|
||||||
use basic_oidc::controllers::assets_controller::assets_route;
|
|
||||||
use basic_oidc::controllers::login_controller::login_route;
|
|
||||||
use basic_oidc::data::app_config::AppConfig;
|
use basic_oidc::data::app_config::AppConfig;
|
||||||
use basic_oidc::data::entity_manager::EntityManager;
|
use basic_oidc::data::entity_manager::EntityManager;
|
||||||
use basic_oidc::data::user::{hash_password, User};
|
use basic_oidc::data::user::{hash_password, User};
|
||||||
|
use basic_oidc::controllers::assets_controller::assets_route;
|
||||||
|
|
||||||
#[get("/health")]
|
#[get("/health")]
|
||||||
async fn health() -> &'static str {
|
fn index() -> &'static str {
|
||||||
"Running"
|
"Running"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_web::main]
|
#[rocket::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> Result<(), rocket::Error> {
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
//env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|
||||||
let config: AppConfig = AppConfig::parse();
|
let rocket = rocket::build()
|
||||||
|
.mount("/", routes![index])
|
||||||
|
.mount("/assets", routes![assets_route])
|
||||||
|
.attach(AdHoc::config::<AppConfig>());
|
||||||
|
let figment = rocket.figment();
|
||||||
|
|
||||||
|
// Initialize application
|
||||||
|
let config: AppConfig = figment.extract().expect("config");
|
||||||
|
|
||||||
if !config.storage_path().exists() {
|
if !config.storage_path().exists() {
|
||||||
log::error!(
|
log::error!(
|
||||||
@ -48,16 +55,5 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.expect("Failed to create initial user!");
|
.expect("Failed to create initial user!");
|
||||||
}
|
}
|
||||||
|
|
||||||
log::info!("Server will listen on {}", config.listen_address);
|
rocket.launch().await
|
||||||
|
|
||||||
HttpServer::new(|| {
|
|
||||||
App::new()
|
|
||||||
.wrap(Logger::default())
|
|
||||||
.service(health)
|
|
||||||
.route("/assets/{path:.*}", web::get().to(assets_route))
|
|
||||||
.route("/login", web::get().to(login_route))
|
|
||||||
})
|
|
||||||
.bind(config.listen_address)?
|
|
||||||
.run()
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<meta name="description" content="Auth service">
|
|
||||||
<title>{{ app_name }} - {{ page_title }}</title>
|
|
||||||
|
|
||||||
<!-- Bootstrap core CSS -->
|
|
||||||
<link href="/assets/css/bootstrap.css" rel="stylesheet" crossorigin="anonymous"/>
|
|
||||||
|
|
||||||
<!-- Favicons -->
|
|
||||||
<meta name="theme-color" content="#7952b3">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bd-placeholder-img {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
text-anchor: middle;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.bd-placeholder-img-lg {
|
|
||||||
font-size: 3.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom styles for this template -->
|
|
||||||
<link href="/assets/css/base_login_page.css" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body class="text-center">
|
|
||||||
|
|
||||||
<main class="form-signin">
|
|
||||||
|
|
||||||
<h1 class="h3 mb-3 fw-normal">{{ page_title }}</h1>
|
|
||||||
|
|
||||||
<div class="alert alert-danger" role="alert">
|
|
||||||
{{ danger }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="alert alert-success" role="alert">
|
|
||||||
{{ success }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
TO_REPLACE
|
|
||||||
{% endblock content %}
|
|
||||||
|
|
||||||
<p class="mt-5 mb-3 text-muted">© 2022 -
|
|
||||||
<script>document.write(new Date().getFullYear())</script>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script src="/assets/js/base_login_page.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,22 +0,0 @@
|
|||||||
{% extends "base_login_page.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<form action="/login" method="post">
|
|
||||||
<div>
|
|
||||||
<div class="form-floating">
|
|
||||||
<input name="mail" type="text" required class="form-control" id="floatingName" placeholder="unsername"
|
|
||||||
value="{{ mail }}">
|
|
||||||
<label for="floatingName">Email address or username</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-floating">
|
|
||||||
<input name="password" type="password" required class="form-control" id="floatingPassword"
|
|
||||||
placeholder="Password">
|
|
||||||
<label for="floatingPassword">Password</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% endblock content %}
|
|
Loading…
x
Reference in New Issue
Block a user