feat: #20 add email in JWT claims
This commit is contained in:
+2
-2
@@ -68,14 +68,14 @@ impl HTTPMessage {
|
||||
#[test]
|
||||
fn test_message() {
|
||||
let mut http_message = HTTPMessage::default();
|
||||
http_message.put("username", "toto");
|
||||
http_message.put("email", "toto@toto.fr");
|
||||
http_message.put("password", "tata");
|
||||
|
||||
let mut json_result: Result<json::JsonValue, String> = http_message.try_into();
|
||||
assert!(json_result.is_ok());
|
||||
|
||||
let mut json = json_result.unwrap();
|
||||
assert!(json.has_key("username"));
|
||||
assert!(json.has_key("email"));
|
||||
assert!(json.has_key("password"));
|
||||
|
||||
let empty_http_message = HTTPMessage::default();
|
||||
|
||||
+3
-3
@@ -22,8 +22,8 @@ async fn handle_get(request: HTTPRequest, config: Config, method: &str) -> HTTPR
|
||||
let mut store = FileStore::new(config.filestore_path.clone());
|
||||
match &request.body {
|
||||
Some(ref b) => {
|
||||
let is_auth = store.is_auth(&b.get_data()).await;
|
||||
if !is_auth {
|
||||
let credentials = store.is_auth(&b.get_data()).await;
|
||||
if credentials.is_none() {
|
||||
return HTTPResponse::as_403();
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ async fn handle_get(request: HTTPRequest, config: Config, method: &str) -> HTTPR
|
||||
}
|
||||
};
|
||||
|
||||
match jwt_signer.sign() {
|
||||
match jwt_signer.sign(credentials.unwrap().email) {
|
||||
Ok(t) => HTTPResponse::send_token(&t),
|
||||
Err(e) => {
|
||||
let message = HTTPMessage::error(&e);
|
||||
|
||||
+11
-2
@@ -1,9 +1,15 @@
|
||||
use crate::config::Config;
|
||||
use jwt_simple::common::VerificationOptions;
|
||||
use jwt_simple::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use tokio::fs;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct JWTCustomClaims {
|
||||
email: String,
|
||||
}
|
||||
|
||||
pub struct JWTSigner {
|
||||
private_key: String,
|
||||
public_key: String,
|
||||
@@ -53,7 +59,7 @@ impl JWTSigner {
|
||||
}
|
||||
|
||||
/// builds and signs the token
|
||||
pub fn sign(&self) -> Result<String, String> {
|
||||
pub fn sign(&self, email: String) -> Result<String, String> {
|
||||
let jwt_key = {
|
||||
match RS384KeyPair::from_pem(&self.private_key) {
|
||||
Ok(k) => k,
|
||||
@@ -62,7 +68,10 @@ impl JWTSigner {
|
||||
}
|
||||
}
|
||||
};
|
||||
let mut claims = Claims::create(Duration::from_hours(self.exp_time));
|
||||
let mut claims = Claims::with_custom_claims(
|
||||
JWTCustomClaims { email },
|
||||
Duration::from_hours(self.exp_time),
|
||||
);
|
||||
claims.issuer = Some(self.issuer.clone());
|
||||
|
||||
match jwt_key.sign(claims) {
|
||||
|
||||
+16
-10
@@ -48,36 +48,40 @@ impl FileStore {
|
||||
}
|
||||
|
||||
/// checks if the credentials exist in the `FileStore`
|
||||
fn auth(&self, username: String, password: String) -> bool {
|
||||
fn auth(&self, email: String, password: String) -> Option<Credentials> {
|
||||
let credentials: Vec<&Credentials> = self
|
||||
.credentials
|
||||
.iter()
|
||||
.filter(|x| x.username == username && x.password == password)
|
||||
.filter(|x| x.email == email && x.password == password)
|
||||
.collect();
|
||||
if credentials.len() == 1 {
|
||||
return true;
|
||||
// no need to store the password again
|
||||
return Some(Credentials::new(
|
||||
credentials[0].email.clone(),
|
||||
"".to_string(),
|
||||
));
|
||||
}
|
||||
false
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Store for FileStore {
|
||||
async fn is_auth(&mut self, data: &json::JsonValue) -> bool {
|
||||
async fn is_auth(&mut self, data: &json::JsonValue) -> Option<Credentials> {
|
||||
// ensure that the store file already exists even after its instanciation
|
||||
if !Path::new(&self.path).is_file() {
|
||||
log::error!("{} path referencing file store does not exist", self.path);
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
let credentials = Credentials::from(data);
|
||||
if credentials.is_empty() {
|
||||
log::error!("unable to parse the credentials correctly from the incoming request");
|
||||
return false;
|
||||
return None;
|
||||
}
|
||||
|
||||
self.parse_contents().await;
|
||||
self.auth(credentials.username, credentials.password)
|
||||
self.auth(credentials.email, credentials.password)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,6 +95,8 @@ async fn test_store() {
|
||||
|
||||
let mut store = FileStore::new(store_path);
|
||||
|
||||
let data = json::parse(r#"{"username": "toto", "password": "tata"}"#).unwrap();
|
||||
assert_eq!(store.is_auth(&data).await, true);
|
||||
let data = json::parse(r#"{"email": "toto@toto.fr", "password": "tata"}"#).unwrap();
|
||||
let credentials = store.is_auth(&data).await;
|
||||
assert_eq!(false, credentials.is_none());
|
||||
assert_eq!(credentials.unwrap().email, "toto@toto.fr");
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,4 +8,4 @@ mod file;
|
||||
mod store;
|
||||
|
||||
pub use file::FileStore;
|
||||
pub use store::Store;
|
||||
pub use store::{Credentials, Store};
|
||||
|
||||
+7
-7
@@ -5,22 +5,22 @@ use crate::utils::extract_json_value;
|
||||
|
||||
#[async_trait]
|
||||
pub trait Store {
|
||||
async fn is_auth(&mut self, data: &json::JsonValue) -> bool;
|
||||
async fn is_auth(&mut self, data: &json::JsonValue) -> Option<Credentials>;
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Credentials {
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl Credentials {
|
||||
pub fn new(username: String, password: String) -> Self {
|
||||
Credentials { username, password }
|
||||
pub fn new(email: String, password: String) -> Self {
|
||||
Credentials { email, password }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.username == "" || self.password == ""
|
||||
self.email == "" || self.password == ""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ impl From<&json::JsonValue> for Credentials {
|
||||
let mut credentials = Credentials::default();
|
||||
match data {
|
||||
json::JsonValue::Object(ref d) => {
|
||||
credentials.username = extract_json_value(&d, "username").unwrap_or("".to_string());
|
||||
credentials.email = extract_json_value(&d, "email").unwrap_or("".to_string());
|
||||
credentials.password = extract_json_value(&d, "password").unwrap_or("".to_string());
|
||||
}
|
||||
_ => return credentials,
|
||||
@@ -50,7 +50,7 @@ fn test_credentials() {
|
||||
is_empty: true
|
||||
},
|
||||
Expect {
|
||||
data: json::parse(r#"{"username":"toto","password": "tata"}"#).unwrap(),
|
||||
data: json::parse(r#"{"email":"toto@toto.fr","password": "tata"}"#).unwrap(),
|
||||
is_empty: false
|
||||
}
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user