ezidam + jwt: get key, import private key, create jwt claims and sign them
This commit is contained in:
parent
ef8d75ecee
commit
e99115e174
14 changed files with 217 additions and 5 deletions
|
|
@ -15,3 +15,4 @@ chrono = { workspace = true }
|
|||
# local crates
|
||||
id = { path = "../id" }
|
||||
database = { path = "../database" }
|
||||
users = { path = "../users" }
|
||||
58
crates/jwt/src/claims.rs
Normal file
58
crates/jwt/src/claims.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use crate::{Error, PrivateKey};
|
||||
use chrono::Duration;
|
||||
use jwt_compact::{Claims, Header, TimeOptions};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use users::User;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JwtClaims {
|
||||
// Standard JWT claims
|
||||
#[serde(rename = "iss")]
|
||||
pub issuer: String,
|
||||
#[serde(rename = "sub")]
|
||||
pub subject: String,
|
||||
#[serde(rename = "aud")]
|
||||
pub audience: String,
|
||||
|
||||
// Custom claims
|
||||
pub username: String,
|
||||
pub email: Option<String>,
|
||||
pub is_admin: bool,
|
||||
pub roles: Vec<String>,
|
||||
}
|
||||
|
||||
impl JwtClaims {
|
||||
pub fn new(
|
||||
issuer: impl Into<String>,
|
||||
audience: impl Into<String>,
|
||||
user: &User,
|
||||
roles: Vec<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
// Standard JWT claims
|
||||
issuer: issuer.into(),
|
||||
subject: user.id().to_string(),
|
||||
audience: audience.into(),
|
||||
|
||||
// Custom claims
|
||||
username: user.username().to_string(),
|
||||
email: user.email().map(String::from),
|
||||
is_admin: user.is_admin(),
|
||||
roles,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign_serialize(self, key: &PrivateKey) -> Result<String, Error> {
|
||||
let header = Header::default().with_key_id(key.id());
|
||||
|
||||
let claims = Claims::<Self>::new(self);
|
||||
|
||||
// Set duration
|
||||
let duration = Duration::minutes(15);
|
||||
let time_options = TimeOptions::default();
|
||||
let claims = claims.set_duration_and_issuance(&time_options, duration);
|
||||
|
||||
key.sign_serialize_jwt(header, claims)
|
||||
}
|
||||
}
|
||||
|
|
@ -44,6 +44,10 @@ impl Key {
|
|||
pub fn public_der(&self) -> &[u8] {
|
||||
&self.public_der
|
||||
}
|
||||
|
||||
pub fn is_revoked(&self) -> bool {
|
||||
self.revoked_at.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DatabaseKeys> for Key {
|
||||
|
|
|
|||
|
|
@ -20,4 +20,7 @@ pub enum Error {
|
|||
|
||||
#[error("Failed to serialize JWK: `{0}`")]
|
||||
JwkSerialization(#[from] serde_json::Error),
|
||||
|
||||
#[error("Failed to create JWT: `{0}`")]
|
||||
JwtCreation(#[from] jwt_compact::CreationError),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::Error;
|
||||
use crate::{Error, JwtClaims};
|
||||
use id::KeyID;
|
||||
use jwt_compact::alg::{RsaPrivateKey, StrongKey};
|
||||
use jwt_compact::alg::{Rsa, RsaPrivateKey, StrongKey};
|
||||
use jwt_compact::{AlgorithmExt, Claims, Header};
|
||||
use rsa::pkcs8::der::zeroize::Zeroizing;
|
||||
use rsa::pkcs8::{DecodePrivateKey, EncodePrivateKey};
|
||||
|
||||
|
|
@ -27,6 +28,18 @@ impl PrivateKey {
|
|||
key: RsaPrivateKey::from_pkcs8_der(der)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
self.id.as_ref()
|
||||
}
|
||||
|
||||
pub fn sign_serialize_jwt(
|
||||
&self,
|
||||
header: Header,
|
||||
claims: Claims<JwtClaims>,
|
||||
) -> Result<String, Error> {
|
||||
Ok(Rsa::ps256().token(header, &claims, &self.key)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
extern crate core;
|
||||
|
||||
mod claims;
|
||||
pub mod database;
|
||||
mod error;
|
||||
mod jwk;
|
||||
mod key;
|
||||
mod token;
|
||||
|
||||
/// Exports
|
||||
/// Export
|
||||
pub use claims::JwtClaims;
|
||||
pub use error::Error;
|
||||
pub use key::generate;
|
||||
pub use key::{PrivateKey, PublicKey};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue