diff --git a/Cargo.toml b/Cargo.toml index 23fb527..5dd188b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,7 @@ base64 = "0.10.0" serde = "1.0.40" serde_json = "1.0.40" serde_derive = "1.0.40" +biscuit = "0.3.1" +ring = "0.16.5" +num = "0.2" +openssl = "0.10.28" diff --git a/src/main.rs b/src/main.rs index 62ce75d..d8f8413 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![deny(warnings)] +extern crate biscuit; extern crate base64; extern crate hyper; extern crate ldap3; @@ -8,6 +9,10 @@ extern crate tokio; extern crate serde_derive; use std::env; +use std::io; +use std::fs; +use std::fs::File; +use std::path::Path; use std::str::{ FromStr, from_utf8, @@ -20,6 +25,34 @@ use hyper::header::{AUTHORIZATION}; use hyper_router::{Route, RouterBuilder, RouterService}; use base64::decode; +use ring::signature::RsaKeyPair; +use biscuit::{ + ClaimsSet, + Empty, + JWT, + RegisteredClaims, + SingleOrMultiple, +}; +use biscuit::jwa::{ + SignatureAlgorithm, + Algorithm, +}; +use biscuit::jwk::{ + RSAKeyParameters, + CommonParameters, + AlgorithmParameters, + JWK, + JWKSet, +}; +use biscuit::jws::{ + Secret, + RegisteredHeader, +}; +use num::BigUint; +use openssl::bn::BigNum; +use openssl::rsa::Rsa; +use openssl::rsa::RsaPrivateKeyBuilder; + use ldap3::{ LdapConn, Scope, SearchEntry }; #[derive(Debug)] @@ -152,30 +185,48 @@ fn auth_handler(req: Request) -> Response { Response::new(Body::from(format!("BasicAuthentication {:?}", user))) } -#[derive(Debug, Serialize)] -struct Key { - pub e: String, -} - -#[derive(Debug, Serialize)] -struct JwksResponse { - pub keys: Vec, +fn jwk_from_pem(file_path: &Path) -> Result, io::Error> { + let key_bytes = fs::read(file_path)?; + let rsa = Rsa::private_key_from_pem(key_bytes.as_slice()).unwrap(); + Ok(JWK { + common: CommonParameters { + algorithm: Some(Algorithm::Signature(SignatureAlgorithm::RS256)), + key_id: Some(file_path.file_name().unwrap().to_str().unwrap().to_string()), + ..Default::default() + }, + algorithm: AlgorithmParameters::RSA(RSAKeyParameters { + n: BigUint::from_bytes_be(&rsa.n().to_vec()), + e: BigUint::from_bytes_be(&rsa.e().to_vec()), + ..Default::default() + }), + additional: Default::default(), + }) } fn get_keys(_req: Request) -> Response { - let key = Key { - e: "what".to_string(), - }; - let mut response = JwksResponse { - keys: Vec::new(), - }; - response.keys.push(key); - - let json_str = serde_json::to_string(&response).unwrap(); + let jwks: Vec> = fs::read_dir("./").unwrap() + .filter_map(|dir_entry| { + let path = dir_entry.unwrap().path(); + let filename = match path.file_name() { + Some(filename) => filename.to_str().unwrap().to_owned(), + None => return None, + }; + let ext = match path.extension() { + Some(ext) => ext.to_str().unwrap().to_owned(), + None => return None, + }; + match ext.as_ref() { + "pem" => Some(jwk_from_pem(path.as_path()).unwrap()), + _ => None, + } + }) + .collect(); + let jwks = JWKSet { keys: jwks }; + let jwks_json = serde_json::to_string(&jwks).unwrap(); Response::builder() .status(StatusCode::OK) .header("Content-Type", "application/json") - .body(Body::from(json_str)) + .body(Body::from(jwks_json)) .unwrap() }