From 2dea604581cafbfbb73443ec2449cda391d12ab7 Mon Sep 17 00:00:00 2001 From: Cara Salter Date: Tue, 28 Jun 2022 07:47:29 -0400 Subject: auth: Initial implementation of auth/begin --- Cargo.lock | 9 +++++++++ Cargo.toml | 4 ++++ src/errors.rs | 21 ++++++++++++++++++-- src/handlers/auth.rs | 55 ++++++++++++++++++++++++++++++++++++++++++---------- 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7242c13..504227c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -498,6 +498,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "0.2.6" @@ -1320,13 +1326,16 @@ version = "0.3.0" dependencies = [ "axum", "axum-macros", + "chrono", "color-eyre", "eyre", + "hex", "hyper", "kankyo", "paseto", "rand", "reqwest", + "ring", "serde", "solarlib", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 0b2ead9..6792e7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,13 @@ kankyo = "0.3" axum-macros = "0.2" paseto = "2" +ring = "0.16" +hex = "0.4" rand = "0.8" +chrono = "0.4" + [dependencies.solarlib] git = "https://git.carathe.dev/solard/solarlib" branch = "master" diff --git a/src/errors.rs b/src/errors.rs index cbec046..f6e00e2 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,5 @@ +use hex::FromHexError; +use ring::error::KeyRejected; use thiserror::Error; use axum::response::{Response, IntoResponse}; @@ -5,6 +7,8 @@ use axum::http::StatusCode; use axum::body; use axum::Json; +use ring::error::Unspecified as RingUnspecified; + #[derive(Debug, Error)] pub enum ServiceError { #[error("Solarlib error: {0}")] @@ -28,12 +32,25 @@ pub enum ServiceError { #[error("Generic: {0}")] Generic(String), - #[error("Paseto: {0}")] - Paseto(#[from] pasetors::errors::Error), + #[error("Invalid PASETO Key: {0}")] + PasetoInvalid(#[from] KeyRejected), +} + +impl From for ServiceError { + fn from(_: FromHexError) -> Self { + ServiceError::Generic(String::from("Could not convert from hex")) + } } +impl From for ServiceError { + fn from(_: RingUnspecified) -> Self { + ServiceError::Generic("Unspecified RNG error".to_string()) + } +} pub type StringResult = std::result::Result; +pub type TokenResult = std::result::Result; + pub type JsonResult = std::result::Result; pub type NoneResult = std::result::Result<(), ServiceError>; diff --git a/src/handlers/auth.rs b/src/handlers/auth.rs index a9ac394..8d65b05 100644 --- a/src/handlers/auth.rs +++ b/src/handlers/auth.rs @@ -1,11 +1,14 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fs::{self, File}}; use axum::{extract::Query, Extension}; use axum_macros::debug_handler; -use pasetors::{claims::Claims, keys::{AsymmetricKeyPair, Generate}, version4::V4}; +use chrono::{Utc, TimeZone, Datelike}; +use ring::{rand::SystemRandom, signature::Ed25519KeyPair}; use uuid::Uuid; -use crate::{errors::{NoneResult, ServiceError}, State}; +use std::io::Write; + +use crate::{errors::{NoneResult, ServiceError, StringResult, TokenResult}, State}; /** @@ -14,21 +17,53 @@ use crate::{errors::{NoneResult, ServiceError}, State}; * for future authentication */ #[debug_handler] -pub async fn begin(Query(params): Query>, Extension(state): Extension) -> NoneResult { +pub async fn begin(Query(params): Query>, Extension(state): Extension) -> TokenResult { if let Some(k) = params.get("key") { if k == &state.gen_key { - let mut claims = Claims::new()?; - claims.non_expiring(); - claims.audience("solard")?; - claims.add_additional("uuid", Uuid::new_v4().to_string())?; + let dt = Utc::now(); + let exp = Utc + .ymd(dt.year() + 1, dt.month(), dt.day()) + .and_hms(0, 0, 0); + let kp = load_or_gen_keypair()?; + + let token = match paseto::tokens::PasetoBuilder::new() + .set_ed25519_key(&kp) + .set_issued_at(Some(dt)) + .set_expiration(&exp) + .set_issuer("solard") + .set_audience("solard") + .set_not_before(&Utc::now()) + .build() { + Ok(token) => token, + Err(_) => { + return Err(ServiceError::Generic(String::from("could not generate paseto key"))); + } + }; - let kp = AsymmetricKeyPair::::generate()?; + return Ok(token.to_string()); + } else { return Err(ServiceError::NotAuthorized); } } else { return Err(ServiceError::Generic("No key supplied".to_string())); } +} + + +fn load_or_gen_keypair() -> Result { + let kp: Ed25519KeyPair; + if let Ok(c) = fs::read_to_string(".keypair") { + kp = Ed25519KeyPair::from_pkcs8(&hex::decode(c)?)?; + } else { + let srand = SystemRandom::new(); + let pkcs8 = Ed25519KeyPair::generate_pkcs8(&srand)?; + + let mut file = File::open(".keypair").unwrap(); + file.write(pkcs8.as_ref()); + + kp = Ed25519KeyPair::from_pkcs8(pkcs8.as_ref())?; + } - Ok(()) + Ok(kp) } -- cgit v1.2.3