feat: support OIDC id_token
- generate JWT id_token in token exchange - store optional nonce in authorization object - switch to RS256 algorithm for JWT signature - add JWKs endpoint to provide OIDC clients with public keys
This commit is contained in:
parent
4763915812
commit
02e16a7e74
32 changed files with 469 additions and 103 deletions
|
|
@ -1,4 +1,5 @@
|
|||
pub const DEFAULT_DB_PATH: &str = "/var/lib/minauthator/minauthator.db";
|
||||
pub const DEFAULT_ASSETS_PATH: &str = "/usr/local/lib/minauthator/assets";
|
||||
pub const DEFAULT_CONFIG_PATH: &str = "/etc/minauthator/config.toml";
|
||||
pub const DEFAULT_SIGNING_KEY_PATH: &str = "/etc/minauthator/secrets/jwt.key.pem";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use std::{env, fs};
|
||||
use std::{env, fs, path::Path};
|
||||
use anyhow::{Result, Context, anyhow};
|
||||
use fully_pub::fully_pub;
|
||||
|
||||
use log::info;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
use crate::{
|
||||
consts::{DEFAULT_CONFIG_PATH, DEFAULT_DB_PATH}, database::prepare_database, models::config::Config, repositories::storage::Storage
|
||||
consts::{DEFAULT_CONFIG_PATH, DEFAULT_DB_PATH, DEFAULT_SIGNING_KEY_PATH},
|
||||
database::prepare_database,
|
||||
models::config::Config,
|
||||
repositories::storage::Storage
|
||||
};
|
||||
|
||||
/// get server config
|
||||
|
|
@ -26,9 +28,18 @@ struct StartKernelConfig {
|
|||
#[derive(Debug, Clone)]
|
||||
#[fully_pub]
|
||||
struct AppSecrets {
|
||||
jwt_secret: String
|
||||
/// RSA keypair (public, private) used to signed the JWT issued by minauthator in PEM conainer format
|
||||
signing_keypair: (Vec<u8>, Vec<u8>)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[fully_pub]
|
||||
struct ComputedConfig {
|
||||
signing_public_key: Vec<u8>,
|
||||
signing_private_key: Vec<u8>
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[fully_pub]
|
||||
struct KernelContext {
|
||||
|
|
@ -37,6 +48,19 @@ struct KernelContext {
|
|||
storage: Storage
|
||||
}
|
||||
|
||||
fn get_signing_keypair(key_path: &str) -> Result<(Vec<u8>, Vec<u8>)> {
|
||||
let key_path = Path::new(key_path);
|
||||
let pub_key_path = key_path.with_extension("pub");
|
||||
let private_key: Vec<u8> = fs::read_to_string(&key_path)
|
||||
.context(format!("Failed to read private key from path {:?}.", key_path))?
|
||||
.as_bytes().to_vec();
|
||||
let public_key: Vec<u8> = fs::read_to_string(&pub_key_path)
|
||||
.context(format!("Failed to read public key from path {:?}.", pub_key_path))?
|
||||
.as_bytes().to_vec();
|
||||
|
||||
Ok((public_key, private_key))
|
||||
}
|
||||
|
||||
pub async fn get_kernel_context(start_config: StartKernelConfig) -> Result<KernelContext> {
|
||||
env_logger::init();
|
||||
let _ = dotenvy::dotenv();
|
||||
|
|
@ -50,10 +74,13 @@ pub async fn get_kernel_context(start_config: StartKernelConfig) -> Result<Kerne
|
|||
let config: Config = get_config(config_path)
|
||||
.expect("Cannot get config.");
|
||||
|
||||
let signing_key_path = config.signing_key.clone().unwrap_or(DEFAULT_SIGNING_KEY_PATH.to_string());
|
||||
|
||||
// optionally load dotenv file
|
||||
let _ = dotenvy::dotenv();
|
||||
|
||||
let secrets = AppSecrets {
|
||||
jwt_secret: env::var("APP_JWT_SECRET")
|
||||
.context("Expected APP_JWT_SECRET environment variable to exists.")?
|
||||
signing_keypair: get_signing_keypair(&signing_key_path)?
|
||||
};
|
||||
|
||||
Ok(KernelContext {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ struct Authorization {
|
|||
client_id: String,
|
||||
scopes: Json<Vec<AuthorizationScope>>,
|
||||
|
||||
nonce: Option<String>,
|
||||
|
||||
/// defined in https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2
|
||||
code: String,
|
||||
last_used_at: Option<DateTime<Utc>>,
|
||||
|
|
|
|||
|
|
@ -66,11 +66,6 @@ struct Role {
|
|||
struct Config {
|
||||
instance: InstanceConfig,
|
||||
applications: Vec<Application>,
|
||||
roles: Vec<Role>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[fully_pub]
|
||||
struct AppSecrets {
|
||||
jwt_secret: String
|
||||
roles: Vec<Role>,
|
||||
signing_key: Option<String>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ enum UserStatus {
|
|||
Active
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Deserialize, Serialize, Debug)]
|
||||
#[derive(sqlx::FromRow, Deserialize, Serialize, Debug, Clone)]
|
||||
#[fully_pub]
|
||||
struct User {
|
||||
/// uuid
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue