Skip to content

Commit

Permalink
Added secret "pepper" (#52)
Browse files Browse the repository at this point in the history
* feat: added secret pepper

* chore: updated secret to use playtext

* chore: removed dbg macro

* chore: updated test manifest
  • Loading branch information
paulobressan authored Jul 22, 2024
1 parent 661b9b2 commit 272db2a
Show file tree
Hide file tree
Showing 11 changed files with 85 additions and 30 deletions.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/bin/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct Config {
addr: String,
db_path: String,
auth: Auth,
secret: String,
kafka_producer: HashMap<String, String>,
kafka_consumer: HashMap<String, String>,
}
Expand All @@ -65,6 +66,7 @@ impl From<Config> for GrpcConfig {
addr: value.addr,
db_path: value.db_path,
auth_url: value.auth.url,
secret: value.secret,
kafka: value.kafka_producer,
}
}
Expand Down
1 change: 1 addition & 0 deletions src/domain/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub struct ProjectSecretCreated {
pub project_id: String,
pub name: String,
pub phc: String,
pub secret: Vec<u8>,
}
into_event!(ProjectSecretCreated);

Expand Down
52 changes: 43 additions & 9 deletions src/domain/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,21 @@ pub async fn create_secret(

let key = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);
let salt_string = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let secret = cmd.secret.to_bytes();

let argon2 = match Argon2::new_with_secret(
secret,
Default::default(),
Default::default(),
Default::default(),
) {
Ok(argon2) => argon2.clone(),
Err(error) => {
error!(?error, "error to configure argon2 with secret");
bail!("internal error")
}
};

let password_hash = argon2
.hash_password(key.to_bytes(), salt_string.as_salt())
.map_err(|err| Error::msg(err.to_string()))?;
Expand All @@ -98,6 +112,7 @@ pub async fn create_secret(
project_id: project.id,
name: cmd.name,
phc: password_hash.to_string(),
secret: secret.to_vec(),
};

event.dispatch(evt.into()).await?;
Expand Down Expand Up @@ -130,10 +145,21 @@ pub async fn verify_secret(

let secrets = cache.find_secret_by_project_id(project_id).await?;

let argon2 = Argon2::default();
let secret = secrets.into_iter().find(|secret| {
let Ok(password_hash) = PasswordHash::new(&secret.phc) else {
error!(project_id, secret_id = secret.id, "error to decode phc");
let secret = secrets.into_iter().find(|project_secret| {
let argon2 = Argon2::new_with_secret(
&project_secret.secret,
Default::default(),
Default::default(),
Default::default(),
)
.unwrap();

let Ok(password_hash) = PasswordHash::new(&project_secret.phc) else {
error!(
project_id,
secret_id = project_secret.id,
"error to decode phc"
);
return false;
};

Expand Down Expand Up @@ -200,16 +226,18 @@ impl From<ProjectCreated> for ProjectCache {
#[derive(Debug, Clone)]
pub struct CreateProjectSecretCmd {
pub credential: Credential,
pub secret: String,
pub id: String,
pub project_id: String,
pub name: String,
}
impl CreateProjectSecretCmd {
pub fn new(credential: Credential, project_id: String, name: String) -> Self {
pub fn new(credential: Credential, secret: String, project_id: String, name: String) -> Self {
let id = Uuid::new_v4().to_string();

Self {
credential,
secret,
id,
project_id,
name,
Expand All @@ -223,6 +251,7 @@ pub struct ProjectSecretCache {
pub project_id: String,
pub name: String,
pub phc: String,
pub secret: Vec<u8>,
}
impl From<ProjectSecretCreated> for ProjectSecretCache {
fn from(value: ProjectSecretCreated) -> Self {
Expand All @@ -231,6 +260,7 @@ impl From<ProjectSecretCreated> for ProjectSecretCache {
project_id: value.project_id,
name: value.name,
phc: value.phc,
secret: value.secret,
}
}
}
Expand Down Expand Up @@ -334,10 +364,11 @@ mod tests {
}
}

const KEY: &str = "dmtr_apikey12e8hvc63gfp8jutwv3t4z6jy2gr8lswa";
const PHC: &str = "$argon2id$v=19$m=19456,t=2,p=1$L3YdRbmEOXUg66MZF9McXQ$h4LohO/+Zvo6xRhcomO7KuIjrM9pAlHeQU9ZwEYMwnM";
const KEY: &str = "dmtr_apikey1g9gyswtcf3zxwd26v4x5jj3jw5wx3sn2";
const PHC: &str = "$argon2id$v=19$m=19456,t=2,p=1$xVIt6Wr/bm1FewVhTr6zgA$nTO6EgGeOYZe7thACrHmFUWND40U4GEQCXKyvqzvRvs";
const SECRET: &str = "fabric@txpipe";
const INVALID_KEY: &str = "dmtr_apikey1xe6xzcjxv9nhycnz2ffnq6m02y7nat9e";
const INVALID_HRP_KEY: &str = "mykey1x9zk7c60wfj8xv6929ykynmnwseehq78";
const INVALID_HRP_KEY: &str = "dmtr_test18pp5vkjzfuuyzwpeg9gk2a2zvsylc5wg";

impl Default for CreateProjectSecretCmd {
fn default() -> Self {
Expand All @@ -346,6 +377,7 @@ mod tests {
id: Uuid::new_v4().to_string(),
project_id: Uuid::new_v4().to_string(),
name: "Key 1".into(),
secret: SECRET.into(),
}
}
}
Expand All @@ -356,6 +388,7 @@ mod tests {
project_id: Uuid::new_v4().to_string(),
name: "Key 1".into(),
phc: PHC.into(),
secret: SECRET.to_bytes().to_vec(),
}
}
}
Expand All @@ -366,6 +399,7 @@ mod tests {
project_id: Uuid::new_v4().to_string(),
name: "Key 1".into(),
phc: PHC.into(),
secret: SECRET.to_bytes().to_vec(),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/driven/cache/migrations/20240606_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ CREATE TABLE IF NOT EXISTS project_secret (
project_id TEXT NOT NULL,
name TEXT NOT NULL,
phc TEXT NOT NULL,
secret BLOB NOT NULL,
FOREIGN KEY(project_id) REFERENCES project(id)
);
8 changes: 5 additions & 3 deletions src/driven/cache/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ impl ProjectDrivenCache for SqliteProjectDrivenCache {
async fn create_secret(&self, secret: &ProjectSecretCache) -> Result<()> {
sqlx::query!(
r#"
INSERT INTO project_secret (id, project_id, name, phc)
VALUES ($1, $2, $3, $4)
INSERT INTO project_secret (id, project_id, name, phc, secret)
VALUES ($1, $2, $3, $4, $5)
"#,
secret.id,
secret.project_id,
secret.name,
secret.phc,
secret.secret
)
.execute(&self.sqlite.db)
.await?;
Expand All @@ -95,7 +96,7 @@ impl ProjectDrivenCache for SqliteProjectDrivenCache {
async fn find_secret_by_project_id(&self, project_id: &str) -> Result<Vec<ProjectSecretCache>> {
let secrets = sqlx::query_as::<_, ProjectSecretCache>(
r#"
SELECT id, project_id, name, phc
SELECT id, project_id, name, phc, secret
FROM project_secret WHERE project_id = $1;
"#,
)
Expand Down Expand Up @@ -143,6 +144,7 @@ impl FromRow<'_, SqliteRow> for ProjectSecretCache {
project_id: row.try_get("project_id")?,
name: row.try_get("name")?,
phc: row.try_get("phc")?,
secret: row.try_get("secret")?,
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/grpc/middlewares/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl tonic::service::Interceptor for AuthenticatorImpl {
return tokio::runtime::Runtime::new().unwrap().block_on(async {
match project::verify_secret(self.cache.clone(), &project_id, &token).await {
Ok(secret) => {
let credential = Credential::ApiKey(secret.id);
let credential = Credential::ApiKey(secret.project_id);
request.extensions_mut().insert(credential);
Ok(request)
}
Expand Down
8 changes: 6 additions & 2 deletions src/drivers/grpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ pub async fn server(config: GrpcConfig) -> Result<()> {
project_cache.clone(),
);

let project_inner =
project::ProjectServiceImpl::new(project_cache.clone(), event_bridge.clone());
let project_inner = project::ProjectServiceImpl::new(
project_cache.clone(),
event_bridge.clone(),
config.secret.clone(),
);
let project_service = ProjectServiceServer::with_interceptor(project_inner, auth.clone());

let resource_inner =
Expand All @@ -62,5 +65,6 @@ pub struct GrpcConfig {
pub addr: String,
pub db_path: String,
pub auth_url: String,
pub secret: String,
pub kafka: HashMap<String, String>,
}
16 changes: 13 additions & 3 deletions src/drivers/grpc/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,20 @@ use crate::domain::{
pub struct ProjectServiceImpl {
pub cache: Arc<dyn ProjectDrivenCache>,
pub event: Arc<dyn EventDrivenBridge>,
pub secret: String,
}

impl ProjectServiceImpl {
pub fn new(cache: Arc<dyn ProjectDrivenCache>, event: Arc<dyn EventDrivenBridge>) -> Self {
Self { cache, event }
pub fn new(
cache: Arc<dyn ProjectDrivenCache>,
event: Arc<dyn EventDrivenBridge>,
secret: String,
) -> Self {
Self {
cache,
event,
secret,
}
}
}

Expand Down Expand Up @@ -59,7 +68,8 @@ impl proto::project_service_server::ProjectService for ProjectServiceImpl {

let req = request.into_inner();

let cmd = CreateProjectSecretCmd::new(credential, req.project_id, req.name);
let cmd =
CreateProjectSecretCmd::new(credential, self.secret.clone(), req.project_id, req.name);

let result =
project::create_secret(self.cache.clone(), self.event.clone(), cmd.clone()).await;
Expand Down
1 change: 1 addition & 0 deletions test/manifest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ data:
rpc.toml: |
addr="0.0.0.0:80"
db_path="test.db"
secret="fabric@txpipe"
[kafka_producer]
"bootstrap.servers" = "redpanda.demeter-kafka.svc.cluster.local:19092"
Expand Down

0 comments on commit 272db2a

Please sign in to comment.