diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 11a1466..564694d 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -185,6 +185,30 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" +[[package]] +name = "bindgen" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b13ce559e6433d360c26305643803cb52cfbabbc2b9c47ce04a58493dfb443" +dependencies = [ + "bitflags", + "cexpr", + "cfg-if 0.1.10", + "clang-sys", + "clap", + "env_logger", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -233,6 +257,21 @@ version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -261,6 +300,32 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clang-sys" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + [[package]] name = "const_fn" version = "0.4.9" @@ -311,7 +376,7 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -406,7 +471,31 @@ version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", +] + +[[package]] +name = "enum-repr" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad30c9c0fa1aaf1ae5010dab11f1117b15d35faf62cda4bbbc53b9987950f18" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] @@ -429,7 +518,7 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crc32fast", "libc", "miniz_oxide", @@ -567,7 +656,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -578,7 +667,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] @@ -715,6 +804,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "hyper" version = "0.14.16" @@ -773,7 +871,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -907,12 +1005,28 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +[[package]] +name = "libloading" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + [[package]] name = "lock_api" version = "0.4.5" @@ -928,7 +1042,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -937,7 +1051,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "generator", "scoped-tls", "serde", @@ -1025,6 +1139,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -1075,6 +1199,30 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "pam-client" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ad089b829c2f58605a72ca23f9387216001b3a67df345df9a42b473decd667" +dependencies = [ + "bitflags", + "enum-repr", + "libc", + "pam-sys", + "rpassword", + "rustversion", +] + +[[package]] +name = "pam-sys" +version = "1.0.0-alpha3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d5e08cf74c37eb6bb11b8a2af8df35e24c3d45738f2ae1f7004ac30ed7cd09" +dependencies = [ + "bindgen", + "libc", +] + [[package]] name = "parity-tokio-ipc" version = "0.9.0" @@ -1106,7 +1254,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall", @@ -1137,6 +1285,12 @@ dependencies = [ "syn", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "1.0.1" @@ -1230,6 +1384,12 @@ dependencies = [ "libc", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.14" @@ -1483,6 +1643,22 @@ dependencies = [ "uncased", ] +[[package]] +name = "rpassword" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.2.3" @@ -1613,7 +1789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer", - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest", "opaque-debug", @@ -1628,6 +1804,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -1747,6 +1929,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "subtle" version = "2.4.1" @@ -1770,7 +1958,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "rand 0.8.4", "redox_syscall", @@ -1778,6 +1966,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thread_local" version = "1.1.3" @@ -1936,7 +2142,7 @@ version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2052,6 +2258,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" @@ -2085,6 +2297,12 @@ dependencies = [ "percent-encoding 1.0.1", ] +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.4" @@ -2119,7 +2337,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -2198,9 +2416,20 @@ dependencies = [ "jsonrpc-core-client", "jsonrpc-derive", "jsonrpc-ipc-server", + "pam-client", "procfs", "rocket", "serde", + "serde_json", +] + +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", ] [[package]] @@ -2219,6 +2448,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 5058485..39f83f0 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -10,7 +10,9 @@ figment = "^0.10" jsonrpc-core = "~18.0" jsonrpc-derive = "~18.0" jsonrpc-ipc-server = "~18.0" +pam-client = "^0.3.1" serde = "^1.0" +serde_json = "^1.0" [dependencies.jsonrpc-core-client] version = "~18.0" diff --git a/backend/src/daemon/auth.rs b/backend/src/daemon/auth.rs new file mode 100644 index 0000000..d41cc50 --- /dev/null +++ b/backend/src/daemon/auth.rs @@ -0,0 +1,15 @@ +use pam_client::{Context, Error, Flag}; +use pam_client::conv_mock::Conversation; + +const PAM_SERVICE: &'static str = "weywot"; + + +pub fn authenticate(username: &str, password: &str) -> Result<(), Error> { + let mut ctx = Context::new( + PAM_SERVICE, + None, + Conversation::with_credentials(username, password) + )?; + ctx.authenticate(Flag::NONE)?; + Ok(()) +} diff --git a/backend/src/daemon/mod.rs b/backend/src/daemon/mod.rs index 412c8c6..9a8f65f 100644 --- a/backend/src/daemon/mod.rs +++ b/backend/src/daemon/mod.rs @@ -1,3 +1,4 @@ +mod auth; mod rpc; use crate::rpc::WeywotRpc; use argh::FromArgs; diff --git a/backend/src/daemon/rpc.rs b/backend/src/daemon/rpc.rs index 0bae1ec..5e88d1f 100644 --- a/backend/src/daemon/rpc.rs +++ b/backend/src/daemon/rpc.rs @@ -1,6 +1,9 @@ +use super::auth; use crate::models::status::DaemonStatus; use crate::rpc::WeywotRpc; use chrono::Local; +use jsonrpc_core::Error as JsonRpcError; +use jsonrpc_core::ErrorCode as JsonRpcErrorCode; use jsonrpc_core::Result as JsonRpcResult; use procfs::process::Process; use std::convert::TryInto; @@ -10,6 +13,26 @@ use std::process; pub struct RpcDaemon; impl WeywotRpc for RpcDaemon { + /// Authenticate a user + /// + /// Authenticates a user with the given username and password. + /// Returns nothing if authetication succeeded, or the PAM error + /// code and message if authentication failed. + fn authenticate( + &self, + username: String, + password: String, + ) -> JsonRpcResult<()> { + match auth::authenticate(&username, &password) { + Ok(_) => Ok(()), + Err(e) => Err(JsonRpcError { + code: JsonRpcErrorCode::ServerError(e.code().repr().into()), + message: e.message().unwrap_or_default().into(), + data: None, + }) + } + } + fn status(&self) -> JsonRpcResult { Ok(DaemonStatus { version: env!("CARGO_PKG_VERSION").into(), diff --git a/backend/src/models/auth.rs b/backend/src/models/auth.rs new file mode 100644 index 0000000..2b758c3 --- /dev/null +++ b/backend/src/models/auth.rs @@ -0,0 +1,4 @@ +use serde::Serialize; + +#[derive(Debug, Serialize)] +pub struct LoginResponse {} diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs index 16a1865..86762d6 100644 --- a/backend/src/models/mod.rs +++ b/backend/src/models/mod.rs @@ -1 +1,2 @@ -pub mod status; \ No newline at end of file +pub mod auth; +pub mod status; diff --git a/backend/src/rpc.rs b/backend/src/rpc.rs index bf1309e..ec91bb0 100644 --- a/backend/src/rpc.rs +++ b/backend/src/rpc.rs @@ -6,4 +6,7 @@ use jsonrpc_derive::rpc; pub trait WeywotRpc { #[rpc(name = "status")] fn status(&self) -> Result; + + #[rpc(name = "authenticate")] + fn authenticate(&self, username: String, password: String) -> Result<()>; } diff --git a/backend/src/server/error.rs b/backend/src/server/error.rs index d974d45..0877edc 100644 --- a/backend/src/server/error.rs +++ b/backend/src/server/error.rs @@ -16,3 +16,7 @@ impl ErrorResponse { } } } + +pub fn error>(status: HttpStatus, message: S) -> ApiError { + (status, Json(ErrorResponse::new(message))) +} diff --git a/backend/src/server/mod.rs b/backend/src/server/mod.rs index d947b72..a9937ba 100644 --- a/backend/src/server/mod.rs +++ b/backend/src/server/mod.rs @@ -62,7 +62,10 @@ pub async fn main() -> Result<(), rocket::Error> { ); rocket::custom(figment) - .mount("/", rocket::routes![routes::status::get_status]) + .mount( + "/", + rocket::routes![routes::status::get_status, routes::auth::login], + ) .attach(AdHoc::config::()) .manage(context) .ignite() diff --git a/backend/src/server/routes/auth.rs b/backend/src/server/routes/auth.rs new file mode 100644 index 0000000..56a40df --- /dev/null +++ b/backend/src/server/routes/auth.rs @@ -0,0 +1,44 @@ +use super::super::context::Context; +use super::super::error::{error, ApiError}; +use crate::models::auth::LoginResponse; +use rocket::form::{Form, FromForm}; +use rocket::http::{Cookie, CookieJar, Status}; +use rocket::serde::json::Json; +use rocket::serde::Serialize; +use rocket::State; +use serde_json; + +#[derive(FromForm)] +pub struct LoginForm<'r> { + username: &'r str, + password: &'r str, +} + +#[derive(Serialize)] +struct AuthCookie { + username: String, +} + +#[rocket::post("/auth/login", data = "
")] +pub async fn login( + context: &State, + cookies: &CookieJar<'_>, + form: Form>, +) -> Result, ApiError> { + let client = context.client().await?; + match client + .authenticate(form.username.into(), form.password.into()) + .await + { + Ok(_) => {} + Err(e) => return Err(error(Status::Unauthorized, e.to_string())), + } + let cookie = AuthCookie { + username: form.username.into(), + }; + cookies.add_private(Cookie::new( + "weywot.auth", + serde_json::to_string(&cookie).unwrap(), + )); + Ok(Json(LoginResponse {})) +} diff --git a/backend/src/server/routes/mod.rs b/backend/src/server/routes/mod.rs index 822c729..86762d6 100644 --- a/backend/src/server/routes/mod.rs +++ b/backend/src/server/routes/mod.rs @@ -1 +1,2 @@ +pub mod auth; pub mod status;