Feat: JWT handling
This commit is contained in:
parent
e1fa45e39b
commit
820f619aeb
7 changed files with 832 additions and 59 deletions
768
Cargo.lock
generated
768
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -68,6 +68,9 @@ tower = "0.4.13"
|
||||||
hyper-util = "0.1.6"
|
hyper-util = "0.1.6"
|
||||||
toml = "0.8.15"
|
toml = "0.8.15"
|
||||||
rust-ini = "0.21.0"
|
rust-ini = "0.21.0"
|
||||||
|
jwt-simple = "0.12.10"
|
||||||
|
config = "0.14.1"
|
||||||
|
dotenvy = "0.15.7"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
caps = "0.5"
|
caps = "0.5"
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,11 @@ pub fn store_device(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
log::debug!("Storing openid user {:#?}", openid_user);
|
log::debug!("Storing openid user {:#?}", openid_user);
|
||||||
let conn = rusqlite::Connection::open(PATH)?;
|
let conn = rusqlite::Connection::open(PATH)?;
|
||||||
|
todo!();
|
||||||
// TODO
|
conn.execute(
|
||||||
|
"INSERT INTO device (name, public_key, apns_token, user_id, ipv4, ipv6, access_token, refresh_token)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
use crate::auth::server::providers::OpenIdUser;
|
use crate::auth::server::providers::{KeypairT, OpenIdUser};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
grpc_defs::{
|
grpc_defs::{
|
||||||
|
|
@ -9,10 +11,13 @@ use super::{
|
||||||
SlackAuthRequest,
|
SlackAuthRequest,
|
||||||
},
|
},
|
||||||
providers::slack::auth,
|
providers::slack::auth,
|
||||||
|
settings::BurrowAuthServerConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
struct BurrowGrpcServer {
|
||||||
struct BurrowGrpcServer;
|
config: Arc<BurrowAuthServerConfig>,
|
||||||
|
jwt_keypair: Arc<KeypairT>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
impl BurrowWeb for BurrowGrpcServer {
|
impl BurrowWeb for BurrowGrpcServer {
|
||||||
|
|
@ -31,19 +36,19 @@ impl BurrowWeb for BurrowGrpcServer {
|
||||||
let jwt = req
|
let jwt = req
|
||||||
.jwt
|
.jwt
|
||||||
.ok_or(Status::invalid_argument("JWT Not existent!"))?;
|
.ok_or(Status::invalid_argument("JWT Not existent!"))?;
|
||||||
let oid_user =
|
let oid_user = OpenIdUser::try_from_jwt(&jwt, &self.jwt_keypair)
|
||||||
OpenIdUser::try_from(&jwt).map_err(|e| Status::invalid_argument(e.to_string()))?;
|
.map_err(|e| Status::invalid_argument(e.to_string()))?;
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_device(&self, request: Request<JwtInfo>) -> Result<Response<Empty>, Status> {
|
async fn delete_device(&self, request: Request<JwtInfo>) -> Result<Response<Empty>, Status> {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_devices(
|
async fn list_devices(
|
||||||
&self,
|
&self,
|
||||||
request: Request<JwtInfo>,
|
request: Request<JwtInfo>,
|
||||||
) -> Result<Response<ListDevicesResponse>, Status> {
|
) -> Result<Response<ListDevicesResponse>, Status> {
|
||||||
unimplemented!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ pub mod db;
|
||||||
pub mod grpc_defs;
|
pub mod grpc_defs;
|
||||||
mod grpc_server;
|
mod grpc_server;
|
||||||
pub mod providers;
|
pub mod providers;
|
||||||
|
pub mod settings;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use axum::{http::StatusCode, routing::post, Router};
|
use axum::{http::StatusCode, routing::post, Router};
|
||||||
|
|
@ -11,9 +12,7 @@ use tokio::signal;
|
||||||
pub async fn serve() -> Result<()> {
|
pub async fn serve() -> Result<()> {
|
||||||
db::init_db()?;
|
db::init_db()?;
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new().route("/device/new", post(device_new));
|
||||||
.route("/slack-auth", post(auth))
|
|
||||||
.route("/device/new", post(device_new));
|
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
|
let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
|
||||||
log::info!("Starting auth server on port 8080");
|
log::info!("Starting auth server on port 8080");
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,65 @@
|
||||||
pub mod slack;
|
pub mod slack;
|
||||||
pub use super::{db, grpc_defs};
|
use self::grpc_defs::JwtInfo;
|
||||||
use anyhow::Result;
|
|
||||||
use grpc_defs::JwtInfo;
|
|
||||||
|
|
||||||
#[derive(serde::Deserialize, Default, Debug)]
|
pub use super::{db, grpc_defs, settings::BurrowAuthServerConfig};
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use jwt_simple::{
|
||||||
|
claims::{Claims, NoCustomClaims},
|
||||||
|
prelude::{Duration, Ed25519KeyPair, EdDSAKeyPairLike, EdDSAPublicKeyLike},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub type KeypairT = Ed25519KeyPair;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct OpenIdUser {
|
pub struct OpenIdUser {
|
||||||
pub sub: String,
|
pub sub: String,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&JwtInfo> for OpenIdUser {
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
type Error = anyhow::Error;
|
struct OpenIDCustomField {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
fn try_from(jwt_info: &JwtInfo) -> Result<Self> {
|
impl OpenIdUser {
|
||||||
todo!()
|
pub fn try_from_jwt(jwt_info: &JwtInfo, keypair: &KeypairT) -> Result<Self> {
|
||||||
|
let claims = keypair
|
||||||
|
.public_key()
|
||||||
|
.verify_token::<OpenIDCustomField>(&jwt_info.jwt, None)?;
|
||||||
|
Ok(Self {
|
||||||
|
sub: claims.subject.ok_or(anyhow!("No Subject!"))?,
|
||||||
|
name: claims.custom.name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JwtInfo {
|
||||||
|
fn try_from_oid(oid_user: OpenIdUser, keypair: &KeypairT) -> Result<Self> {
|
||||||
|
let claims = Claims::with_custom_claims(
|
||||||
|
OpenIDCustomField { name: oid_user.name },
|
||||||
|
Duration::from_days(10),
|
||||||
|
)
|
||||||
|
.with_subject(oid_user.sub);
|
||||||
|
let jwt = keypair.sign(claims)?;
|
||||||
|
Ok(Self { jwt })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_jwt() -> Result<()> {
|
||||||
|
let key_pair = Ed25519KeyPair::generate();
|
||||||
|
let sample_usr = OpenIdUser {
|
||||||
|
sub: "Spanish".into(),
|
||||||
|
name: "Inquisition".into(),
|
||||||
|
};
|
||||||
|
let encoded = JwtInfo::try_from_oid(sample_usr.clone(), &key_pair)?;
|
||||||
|
let decoded = OpenIdUser::try_from_jwt(&encoded, &key_pair)?;
|
||||||
|
assert_eq!(decoded, sample_usr);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
23
burrow/src/auth/server/settings.rs
Normal file
23
burrow/src/auth/server/settings.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use config::{Config, ConfigError, Environment};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct BurrowAuthServerConfig {
|
||||||
|
jwt_secret_key: String,
|
||||||
|
jwt_public_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BurrowAuthServerConfig {
|
||||||
|
pub fn new() -> Result<Self, ConfigError> {
|
||||||
|
let s = Config::builder()
|
||||||
|
.add_source(Environment::default())
|
||||||
|
.build()?;
|
||||||
|
s.try_deserialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new config that includes the dotenv
|
||||||
|
pub fn new_dotenv() -> Result<Self, ConfigError> {
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue