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,14 +6,12 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "3.1.6", features = ["derive", "env"] }
|
||||
actix-web = "4"
|
||||
rocket = "0.5.0-rc.1"
|
||||
rocket_dyn_templates = { version = "0.1.0-rc.1", features = ["tera"] }
|
||||
include_dir = "0.7.2"
|
||||
log = "0.4.16"
|
||||
serde_json = "1.0.79"
|
||||
env_logger = "0.9.0"
|
||||
serde = { version = "1.0.136", features = ["derive"] }
|
||||
bcrypt = "0.12.1"
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
mime_guess = "2.0.4"
|
||||
askama = "0.11.1"
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
@ -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();
|
||||
})
|
@ -3,7 +3,4 @@ pub const USERS_LIST_FILE: &str = "users.json";
|
||||
|
||||
/// Default built-in credentials
|
||||
pub const DEFAULT_ADMIN_USERNAME: &str = "admin";
|
||||
pub const DEFAULT_ADMIN_PASSWORD: &str = "admin";
|
||||
|
||||
/// App name
|
||||
pub const APP_NAME: &str = "Basic OIDC";
|
||||
pub const DEFAULT_ADMIN_PASSWORD: &str = "admin";
|
@ -1,20 +1,22 @@
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use actix_web::{HttpResponse, web};
|
||||
use include_dir::{Dir, include_dir};
|
||||
use rocket::http::{ContentType, Status};
|
||||
|
||||
/// Assets directory
|
||||
static ASSETS_DIR: Dir = include_dir!("$CARGO_MANIFEST_DIR/assets");
|
||||
|
||||
pub async fn assets_route(path: web::Path<String>) -> HttpResponse {
|
||||
let path: &Path = path.as_ref().as_ref();
|
||||
match ASSETS_DIR.get_file(path) {
|
||||
None => HttpResponse::NotFound().body("404 Not found"),
|
||||
#[get("/<file..>")]
|
||||
pub fn assets_route(file: PathBuf) -> (Status, (ContentType, &'static [u8])) {
|
||||
match ASSETS_DIR.get_file(file) {
|
||||
None =>
|
||||
(Status::NotFound, (ContentType::Text, "404 Not found".as_bytes())),
|
||||
Some(file) => {
|
||||
let res = mime_guess::from_path(path).first_or_octet_stream();
|
||||
HttpResponse::Ok()
|
||||
.content_type(res.to_string())
|
||||
.body(file.contents())
|
||||
(Status::Ok, (
|
||||
ContentType::from_extension(file.path().extension().unwrap_or_default()
|
||||
.to_string_lossy().as_ref())
|
||||
.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 login_controller;
|
||||
pub mod assets_controller;
|
@ -1,20 +1,11 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
use rocket::serde::Deserialize;
|
||||
use crate::constants::USERS_LIST_FILE;
|
||||
|
||||
/// Basic OIDC provider
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct AppConfig {
|
||||
/// Listen address
|
||||
#[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,
|
||||
storage_path: PathBuf,
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
@ -23,6 +14,6 @@ impl AppConfig {
|
||||
}
|
||||
|
||||
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>,
|
||||
}
|
||||
|
||||
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
|
||||
pub fn open_or_create<A: AsRef<Path>>(path: A) -> Res<Self> {
|
||||
if !path.as_ref().is_file() {
|
||||
|
@ -1,3 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
|
||||
pub mod data;
|
||||
pub mod utils;
|
||||
pub mod constants;
|
||||
|
40
src/main.rs
40
src/main.rs
@ -1,24 +1,31 @@
|
||||
use actix_web::{App, get, HttpServer, web};
|
||||
use actix_web::middleware::Logger;
|
||||
use clap::Parser;
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
|
||||
use rocket::fairing::AdHoc;
|
||||
|
||||
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::entity_manager::EntityManager;
|
||||
use basic_oidc::data::user::{hash_password, User};
|
||||
use basic_oidc::controllers::assets_controller::assets_route;
|
||||
|
||||
#[get("/health")]
|
||||
async fn health() -> &'static str {
|
||||
fn index() -> &'static str {
|
||||
"Running"
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||
#[rocket::main]
|
||||
async fn main() -> Result<(), rocket::Error> {
|
||||
//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() {
|
||||
log::error!(
|
||||
@ -48,16 +55,5 @@ async fn main() -> std::io::Result<()> {
|
||||
.expect("Failed to create initial user!");
|
||||
}
|
||||
|
||||
log::info!("Server will listen on {}", config.listen_address);
|
||||
|
||||
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
|
||||
rocket.launch().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