Validate token
This commit is contained in:
parent
2c0104ec2d
commit
1667270d73
@ -1,8 +1,12 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix::{Addr, Message};
|
||||
use chrono::prelude::*;
|
||||
use hmac::digest::KeyInit;
|
||||
use hmac::Hmac;
|
||||
use sha2::Sha256;
|
||||
|
||||
use crate::database::{Database, TokenByJti};
|
||||
use crate::model::{AccountId, Audience, Token, TokenString};
|
||||
@ -73,7 +77,7 @@ pub struct CreateToken {
|
||||
|
||||
token_async_handler!(CreateToken, create_token, (Token, TokenString));
|
||||
|
||||
async fn create_token(
|
||||
pub(crate) async fn create_token(
|
||||
msg: CreateToken,
|
||||
db: Addr<Database>,
|
||||
secret: Arc<String>,
|
||||
@ -107,19 +111,9 @@ async fn create_token(
|
||||
};
|
||||
|
||||
let token_string = {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use hmac::{Hmac, Mac};
|
||||
use jwt::SignWithKey;
|
||||
use sha2::Sha256;
|
||||
|
||||
let key: Hmac<Sha256> = match Hmac::new_from_slice(secret.as_bytes()) {
|
||||
Ok(key) => key,
|
||||
Err(e) => {
|
||||
log::error!("{e:?}");
|
||||
return Err(Error::SaveInternal);
|
||||
}
|
||||
};
|
||||
let key: Hmac<Sha256> = build_key(secret)?;
|
||||
let mut claims = BTreeMap::new();
|
||||
|
||||
// cti (customer id): Customer uuid identifier used by payment service
|
||||
@ -168,21 +162,11 @@ pub(crate) async fn validate(
|
||||
db: Addr<Database>,
|
||||
secret: Arc<String>,
|
||||
) -> Result<(Token, bool)> {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use hmac::{Hmac, Mac};
|
||||
use jwt::VerifyWithKey;
|
||||
use sha2::Sha256;
|
||||
|
||||
log::info!("Validating token {:?}", msg.token);
|
||||
|
||||
let key: Hmac<Sha256> = match Hmac::new_from_slice(secret.as_bytes()) {
|
||||
Ok(key) => key,
|
||||
Err(e) => {
|
||||
log::error!("{e:?}");
|
||||
return Err(Error::ValidateInternal);
|
||||
}
|
||||
};
|
||||
let key: Hmac<Sha256> = build_key(secret)?;
|
||||
let claims: BTreeMap<String, String> = match msg.token.verify_with_key(&key) {
|
||||
Ok(claims) => claims,
|
||||
_ => return Err(Error::Validate),
|
||||
@ -209,59 +193,72 @@ pub(crate) async fn validate(
|
||||
}
|
||||
};
|
||||
|
||||
match (claims.get("cti"), &token.customer_id) {
|
||||
(Some(cti), id) => {
|
||||
if !uuid::Uuid::from_str(cti)
|
||||
.map(|u| u == *id)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Ok((token, false));
|
||||
}
|
||||
}
|
||||
_ => return Ok((token, false)),
|
||||
if !validate_pair(&claims, "cti", token.customer_id, validate_uuid) {
|
||||
return Ok((token, false));
|
||||
}
|
||||
// if !validate_pair(&claims, "arl", token.role, |left, right| right == left) {
|
||||
// return Ok((token, false));
|
||||
// }
|
||||
match (claims.get("arl"), &token.role) {
|
||||
(Some(arl), role) if arl == role.as_str() => {}
|
||||
(Some(arl), role) if role == arl.as_str() => {}
|
||||
_ => return Ok((token, false)),
|
||||
}
|
||||
match (claims.get("iss"), &token.issuer) {
|
||||
(Some(iss), issuer) if iss == issuer => {}
|
||||
_ => return Ok((token, false)),
|
||||
}
|
||||
match (claims.get("sub"), &token.subject) {
|
||||
(Some(sub), subject) => {
|
||||
if !sub
|
||||
.parse::<i32>()
|
||||
.map(|n| n == *subject)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Ok((token, false));
|
||||
}
|
||||
}
|
||||
_ => return Ok((token, false)),
|
||||
if !validate_pair(&claims, "sub", token.subject, validate_num) {
|
||||
return Ok((token, false));
|
||||
}
|
||||
|
||||
match (claims.get("aud"), &token.audience) {
|
||||
(Some(aud), audience) if aud == audience.as_str() => {}
|
||||
_ => return Ok((token, false)),
|
||||
}
|
||||
match (claims.get("exp"), &token.expiration_time) {
|
||||
(Some(left), right) if validate_time(left, right) => {}
|
||||
_ => return Ok((token, false)),
|
||||
|
||||
if !validate_pair(&claims, "exp", &token.expiration_time, validate_time) {
|
||||
return Ok((token, false));
|
||||
}
|
||||
match (claims.get("nbt"), &token.not_before_time) {
|
||||
(Some(left), right) if validate_time(left, right) => {}
|
||||
_ => return Ok((token, false)),
|
||||
if !validate_pair(&claims, "nbt", &token.not_before_time, validate_time) {
|
||||
return Ok((token, false));
|
||||
}
|
||||
match (claims.get("iat"), &token.issued_at_time) {
|
||||
(Some(left), right) if validate_time(left, right) => {}
|
||||
_ => return Ok((token, false)),
|
||||
if !validate_pair(&claims, "iat", &token.issued_at_time, validate_time) {
|
||||
return Ok((token, false));
|
||||
}
|
||||
|
||||
Ok((token, true))
|
||||
}
|
||||
|
||||
fn build_key(secret: Arc<String>) -> Result<Hmac<Sha256>> {
|
||||
match Hmac::new_from_slice(secret.as_bytes()) {
|
||||
Ok(key) => Ok(key),
|
||||
Err(e) => {
|
||||
log::error!("{e:?}");
|
||||
Err(Error::ValidateInternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_pair<F, V>(claims: &BTreeMap<String, String>, key: &str, v: V, cmp: F) -> bool
|
||||
where
|
||||
F: FnOnce(&str, V) -> bool,
|
||||
V: PartialEq,
|
||||
{
|
||||
claims.get(key).map(|s| cmp(s, v)).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn validate_time(left: &str, right: &NaiveDateTime) -> bool {
|
||||
chrono::DateTime::parse_from_str(left, "%+")
|
||||
.map(|t| t.naive_utc() == *right)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn validate_num(left: &str, right: i32) -> bool {
|
||||
left.parse::<i32>().map(|n| n == right).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn validate_uuid(left: &str, right: uuid::Uuid) -> bool {
|
||||
uuid::Uuid::from_str(left)
|
||||
.map(|u| u == right)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ pub enum OrderStatus {
|
||||
Refunded,
|
||||
}
|
||||
|
||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
||||
#[derive(sqlx::Type, Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
||||
#[sqlx(rename_all = "snake_case")]
|
||||
pub enum Role {
|
||||
#[display(fmt = "Adminitrator")]
|
||||
@ -40,6 +40,12 @@ pub enum Role {
|
||||
User,
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Role {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.as_str() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl Role {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
|
Loading…
Reference in New Issue
Block a user