Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(db): add ldap_credential table #3612

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ee/tabby-db/migrations/0041_ldap-credential.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE ldap_credential;
23 changes: 23 additions & 0 deletions ee/tabby-db/migrations/0041_ldap-credential.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
CREATE TABLE ldap_credential(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,

host STRING NOT NULL,
port INTEGER NOT NULL DEFAULT 389,

bind_dn STRING NOT NULL,
bind_password STRING NOT NULL,
base_dn STRING NOT NULL,
user_filter STRING NOT NULL,

-- enum of none, starttls, ldaps
encryption STRING NOT NULL DEFAULT 'none',
zwpaper marked this conversation as resolved.
Show resolved Hide resolved
skip_tls_verify BOOLEAN NOT NULL DEFAULT FALSE,

--- the attribute to be used as the Tabby user email address
email_attribute STRING NOT NULL DEFAULT 'email',
--- the attribute to be used as the Tabby user name
name_attribute STRING NOT NULL DEFAULT 'name',

created_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')),
updated_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now'))
);
Binary file modified ee/tabby-db/schema.sqlite
Binary file not shown.
18 changes: 18 additions & 0 deletions ee/tabby-db/schema/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,21 @@ CREATE TABLE read_notifications(
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY(notification_id) REFERENCES notifications(id) ON DELETE CASCADE
);
CREATE TABLE ldap_credential(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
host STRING NOT NULL,
port INTEGER NOT NULL DEFAULT 389,
bind_dn STRING NOT NULL,
bind_password STRING NOT NULL,
base_dn STRING NOT NULL,
user_filter STRING NOT NULL,
-- enum of none, starttls, ldaps
encryption STRING NOT NULL DEFAULT 'none',
skip_tls_verify BOOLEAN NOT NULL DEFAULT FALSE,
--- the attribute to be used as the Tabby user email address
email_attribute STRING NOT NULL DEFAULT 'email',
--- the attribute to be used as the Tabby user name
name_attribute STRING NOT NULL DEFAULT 'name',
created_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')),
updated_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now'))
);
1,396 changes: 727 additions & 669 deletions ee/tabby-db/schema/schema.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
224 changes: 224 additions & 0 deletions ee/tabby-db/src/ldap_credential.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
use anyhow::Result;
use chrono::{DateTime, Utc};
use sqlx::query;

use crate::DbConn;

pub struct LdapCredentialDAO {
pub host: String,
pub port: i64,

pub bind_dn: String,
pub bind_password: String,
pub base_dn: String,
pub user_filter: String,

pub encryption: String,
pub skip_tls_verify: bool,

pub email_attribute: String,
pub name_attribute: String,

pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}

impl DbConn {
pub async fn update_ldap_credential(
&self,
host: &str,
port: i32,
bind_dn: &str,
bind_password: &str,
base_dn: &str,
user_filter: &str,
encryption: &str,
skip_tls_verify: bool,
email_attribute: &str,
name_attribute: &str,
) -> Result<()> {
// only support one ldap credential, so id is always 1
query!(
r#"INSERT INTO ldap_credential (
id,
host,
port,
bind_dn,
bind_password,
base_dn,
user_filter,
encryption,
skip_tls_verify,
email_attribute,
name_attribute
)
VALUES (1, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
ON CONFLICT (id) DO UPDATE SET
host = excluded.host,
port = excluded.port,
bind_dn = excluded.bind_dn,
bind_password = excluded.bind_password,
base_dn = excluded.base_dn,
user_filter = excluded.user_filter,
encryption = excluded.encryption,
skip_tls_verify = excluded.skip_tls_verify,
email_attribute = excluded.email_attribute,
name_attribute = excluded.name_attribute,
updated_at = datetime('now')"#,
host,
port,
bind_dn,
bind_password,
base_dn,
user_filter,
encryption,
skip_tls_verify,
email_attribute,
name_attribute,
)
.execute(&self.pool)
.await?;
Ok(())
}

pub async fn delete_ldap_credential(&self) -> Result<()> {
// only support one ldap credential, so id is always 1
query!("DELETE FROM ldap_credential WHERE id = 1")
.execute(&self.pool)
.await?;
Ok(())
}

pub async fn read_ldap_credential(&self) -> Result<Option<LdapCredentialDAO>> {
let token = sqlx::query_as!(
LdapCredentialDAO,
r#"SELECT
host as "host: String",
port,
bind_dn as "bind_dn: String",
bind_password as "bind_password: String",
base_dn as "base_dn: String",
user_filter as "user_filter: String",
encryption as "encryption: String",
skip_tls_verify,
email_attribute as "email_attribute: String",
name_attribute as "name_attribute: String",
created_at as "created_at: DateTime<Utc>",
updated_at as "updated_at: DateTime<Utc>"
FROM ldap_credential
WHERE id = 1"#,
)
.fetch_optional(&self.pool)
.await?;
Ok(token)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn test_update_ldap_credential() {
let conn = DbConn::new_in_memory().await.unwrap();

// test insert
conn.update_ldap_credential(
"host",
389,
"bind_dn",
"bind_password",
"base_dn",
"user_filter",
"encryption",
true,
"email_attribute",
"name_attribute",
)
.await
.unwrap();
let res = conn.read_ldap_credential().await.unwrap().unwrap();
assert_eq!(res.host, "host");
assert_eq!(res.port, 389);
assert_eq!(res.bind_dn, "bind_dn");
assert_eq!(res.bind_password, "bind_password");
assert_eq!(res.base_dn, "base_dn");
assert_eq!(res.user_filter, "user_filter");
assert_eq!(res.encryption, "encryption");
assert!(res.skip_tls_verify);
assert_eq!(res.email_attribute, "email_attribute");
assert_eq!(res.name_attribute, "name_attribute");
let created_at = res.created_at;
let updated_at = res.updated_at;
assert!(created_at > Utc::now() - chrono::Duration::seconds(2));
assert!(updated_at > Utc::now() - chrono::Duration::seconds(2));

// test update
// sleep for a while to make sure updated_at is different
tokio::time::sleep(std::time::Duration::from_secs(2)).await;

conn.update_ldap_credential(
"host_2",
389,
"bind_dn_2",
"bind_password_2",
"base_dn_2",
"user_filter_2",
"encryption_2",
false,
"email_attribute_2",
"name_attribute_2",
)
.await
.unwrap();
let res = conn.read_ldap_credential().await.unwrap().unwrap();
assert_eq!(res.host, "host_2");
assert_eq!(res.port, 389);
assert_eq!(res.bind_dn, "bind_dn_2");
assert_eq!(res.bind_password, "bind_password_2");
assert_eq!(res.base_dn, "base_dn_2");
assert_eq!(res.user_filter, "user_filter_2");
assert_eq!(res.encryption, "encryption_2");
assert!(!res.skip_tls_verify);
assert_eq!(res.email_attribute, "email_attribute_2");
assert_eq!(res.name_attribute, "name_attribute_2");
assert_eq!(res.created_at, created_at);
assert!(res.updated_at > updated_at);

// make sure only one row in the table
let res = sqlx::query_scalar!("SELECT COUNT(*) FROM ldap_credential")
.fetch_one(&conn.pool)
.await
.unwrap();
assert_eq!(res, 1);
}

#[tokio::test]
async fn test_delete_ldap_credential() {
let conn = DbConn::new_in_memory().await.unwrap();

conn.update_ldap_credential(
"host",
389,
"bind_dn",
"bind_password",
"base_dn",
"user_filter",
"encryption",
true,
"email_attribute",
"name_attribute",
)
.await
.unwrap();

// make sure inserted
let res = conn.read_ldap_credential().await.unwrap();
assert!(res.is_some());

// delete
conn.delete_ldap_credential().await.unwrap();
let res = conn.read_ldap_credential().await.unwrap();
assert!(res.is_none());
}
}
1 change: 1 addition & 0 deletions ee/tabby-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod email_setting;
mod integrations;
mod invitations;
mod job_runs;
mod ldap_credential;
#[cfg(test)]
mod migration_tests;
mod notifications;
Expand Down
Loading