Store jwt secret in database
This commit is contained in:
parent
95914653e0
commit
7cc19bc1cd
|
@ -59,9 +59,8 @@ pub struct AuthResponse {
|
|||
issued_at: String,
|
||||
}
|
||||
|
||||
/// In the returned UserToken::user, only the username is specified
|
||||
fn create_jwt_token(account: Option<&str>, scopes: Vec<Scope>) -> anyhow::Result<TokenInfo> {
|
||||
let key: Hmac<Sha256> = Hmac::new_from_slice(b"some-secret")?;
|
||||
fn create_jwt_token(jwt_key: String, account: Option<&str>, scopes: Vec<Scope>) -> anyhow::Result<TokenInfo> {
|
||||
let key: Hmac<Sha256> = Hmac::new_from_slice(jwt_key.as_bytes())?;
|
||||
|
||||
let now = chrono::offset::Utc::now();
|
||||
|
||||
|
@ -186,7 +185,8 @@ pub async fn auth_basic_get(
|
|||
scope.actions.retain(|a| *a == Action::Pull);
|
||||
}
|
||||
|
||||
let token = create_jwt_token(None, auth.scope).map_err(|_| {
|
||||
let token = create_jwt_token(state.config.jwt_key.clone(), None, auth.scope)
|
||||
.map_err(|_| {
|
||||
error!("Failed to create jwt token!");
|
||||
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
|
@ -290,7 +290,8 @@ pub async fn auth_basic_get(
|
|||
debug!("User password is correct");
|
||||
|
||||
let now = SystemTime::now();
|
||||
let token = create_jwt_token(Some(account), vec![]).map_err(|_| {
|
||||
let token = create_jwt_token(state.config.jwt_key.clone(), Some(account), vec![])
|
||||
.map_err(|_| {
|
||||
error!("Failed to create jwt token!");
|
||||
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
|
|
|
@ -71,6 +71,8 @@ pub struct Config {
|
|||
pub database: DatabaseConfig,
|
||||
pub storage: StorageConfig,
|
||||
pub tls: Option<TlsConfig>,
|
||||
#[serde(skip)]
|
||||
pub jwt_key: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use async_trait::async_trait;
|
||||
use sqlx::{Sqlite, Pool};
|
||||
use hmac::{Hmac, digest::KeyInit};
|
||||
use rand::{Rng, distributions::Alphanumeric};
|
||||
use sha2::Sha256;
|
||||
use sqlx::{Sqlite, Pool, sqlite::SqliteError};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use chrono::{DateTime, Utc, NaiveDateTime, TimeZone};
|
||||
|
@ -8,12 +11,13 @@ use crate::dto::{Tag, user::{User, RepositoryPermissions, RegistryUserType, Perm
|
|||
|
||||
#[async_trait]
|
||||
pub trait Database {
|
||||
|
||||
// Digest related functions
|
||||
|
||||
/// Create the tables in the database
|
||||
async fn create_schema(&self) -> anyhow::Result<()>;
|
||||
|
||||
async fn get_jwt_secret(&self) -> anyhow::Result<String>;
|
||||
|
||||
// Tag related functions
|
||||
|
||||
/// Get tags associated with a repository
|
||||
|
@ -67,14 +71,56 @@ pub trait Database {
|
|||
#[async_trait]
|
||||
impl Database for Pool<Sqlite> {
|
||||
async fn create_schema(&self) -> anyhow::Result<()> {
|
||||
let orca_version = "0.1.0";
|
||||
let schema_version = "0.0.1";
|
||||
|
||||
let row: Option<(u32, )> = match sqlx::query_as("SELECT COUNT(1) FROM orca WHERE \"schema_version\" = ?")
|
||||
.bind(schema_version)
|
||||
.fetch_one(self).await {
|
||||
Ok(row) => Some(row),
|
||||
Err(e) => match e {
|
||||
sqlx::Error::RowNotFound => {
|
||||
None
|
||||
},
|
||||
// ignore no such table errors
|
||||
sqlx::Error::Database(b) if b.message().starts_with("no such table") => None,
|
||||
_ => {
|
||||
return Err(anyhow::Error::new(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if row.is_none() || row.unwrap().0 == 0 {
|
||||
let jwt_sec: String = rand::thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(16)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
// create schema
|
||||
// TODO: Check if needed
|
||||
sqlx::query(include_str!("schemas/schema.sql"))
|
||||
.execute(self).await?;
|
||||
|
||||
debug!("Created database schema");
|
||||
|
||||
sqlx::query("INSERT INTO orca(orca_version, schema_version, jwt_secret) VALUES (?, ?, ?)")
|
||||
.bind(orca_version)
|
||||
.bind(schema_version)
|
||||
.bind(jwt_sec)
|
||||
.execute(self).await?;
|
||||
debug!("Inserted information about orca!");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_jwt_secret(&self) -> anyhow::Result<String> {
|
||||
let rows: (String, ) = sqlx::query_as("SELECT jwt_secret FROM orca WHERE id = (SELECT max(id) FROM orca)")
|
||||
.fetch_one(self).await?;
|
||||
|
||||
Ok(rows.0)
|
||||
}
|
||||
|
||||
async fn link_manifest_layer(&self, manifest_digest: &str, layer_digest: &str) -> anyhow::Result<()> {
|
||||
sqlx::query("INSERT INTO manifest_layers(manifest, layer_digest) VALUES (?, ?)")
|
||||
.bind(manifest_digest)
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
CREATE TABLE IF NOT EXISTS orca (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
orca_version TEXT NOT NULL,
|
||||
schema_version TEXT NOT NULL,
|
||||
jwt_secret TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS projects (
|
||||
name TEXT NOT NULL UNIQUE PRIMARY KEY,
|
||||
-- 0 = private, 1 = public
|
||||
|
|
|
@ -69,7 +69,7 @@ async fn change_request_paths<B>(mut request: Request<B>, next: Next<B>) -> Resu
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let config = Config::new()
|
||||
let mut config = Config::new()
|
||||
.expect("Failure to parse config!");
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
|
@ -92,6 +92,9 @@ async fn main() -> anyhow::Result<()> {
|
|||
.connect_with(connection_options).await?;
|
||||
pool.create_schema().await?;
|
||||
|
||||
// set jwt key
|
||||
config.jwt_key = pool.get_jwt_secret().await?;
|
||||
|
||||
let storage_driver: Mutex<Box<dyn StorageDriver>> = match &config.storage {
|
||||
StorageConfig::Filesystem(fs) => {
|
||||
Mutex::new(Box::new(FilesystemDriver::new(&fs.path)))
|
||||
|
|
Loading…
Reference in New Issue