Skip to content

Commit ec47410

Browse files
authored
Reworking the Canyon Connector (#38)
* #upgrade The Canyon database connector has been reworked, simpliying the process. The monster trasmute for get a mutable reference to a connect due to the Tiberius query method has been eliminated * db_type property of the properties of the datasource moved to the root of the configuration for a datasource * Bumped the toml dependency to 0.7.3. This forced us to change from borrowed to owned types in the structs that holds the user configuration * #feature - reworked the authentication properties for the configuration file, by giving them a unique spot * #feature - Auth property is mandatory for every datasource, looking forward to get rid out of the db_type property, since it will be inferred from the auth declaration * #feature - Removed the db_type field from the options of the configuration file. The in-use per datasource database type will be inferred from the auth key * #feature - Added a test for the `SqlServerAuth` integrated auth option * Adding the required features for working with the tiberius integrated authentication system * Separating with cfg features the conditional different libraries by target to enable integrated auth for tiberius (MSSQL) * Being more specific with targets for the CI process * Upgrading the Rust version for the VMs * Installing vendored OpenSSL * Trying for UNIX based systems to solve the issue with Kerberos by installing their missing system headers * Getting rid out of the installation of the openssl vendored. Propagating the installation of the gssapi headers to the others UNIX based actions * Adding the gssapi headers to the other steps. Bumped the syn deps * Disabling a doc tests in the canyon-macro module that was provoking linker issues under msvc envs * Correct typo in the CI action * v0.2.0 * #feature - #[cfg(feature = "mssql-integrated-auth")]
1 parent 5409cd1 commit ec47410

21 files changed

Lines changed: 300 additions & 219 deletions

File tree

.github/workflows/code-coverage.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ jobs:
2525
run: |
2626
rustup toolchain install nightly
2727
rustup override set nightly
28+
29+
- name: Make the USER own the working directory. Installing `gssapi` headers
30+
if: ${{ matrix.os == 'ubuntu-latest' }}
31+
run: |
32+
sudo chown -R $USER:$USER ${{ github.workspace }}
33+
sudo apt -y install gcc libgssapi-krb5-2 libkrb5-dev libsasl2-modules-gssapi-mit
2834
2935
- name: Caching cargo dependencies
3036
id: project-cache

.github/workflows/code-quality.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,30 @@ jobs:
1515
steps:
1616
- uses: actions/checkout@v3
1717

18+
- name: Make the USER own the working directory. Installing `gssapi` headers
19+
run: |
20+
sudo chown -R $USER:$USER ${{ github.workspace }}
21+
sudo apt -y install gcc libgssapi-krb5-2 libkrb5-dev libsasl2-modules-gssapi-mit
22+
1823
- name: Caching project dependencies
1924
id: project-cache
2025
uses: Swatinem/rust-cache@v2
2126

2227
- uses: hecrj/setup-rust-action@v1
2328
with:
2429
components: clippy
25-
- run: cargo clippy --workspace --all-targets --verbose --all-features -- -A clippy::question_mark
30+
- run: cargo clippy --workspace --all-targets --verbose --all-features
2631
rustfmt:
2732
name: Verify code formatting
2833
runs-on: ubuntu-latest
2934
steps:
3035
- uses: actions/checkout@v3
3136

37+
- name: Make the USER own the working directory. Installing `gssapi` headers
38+
run: |
39+
sudo chown -R $USER:$USER ${{ github.workspace }}
40+
sudo apt -y install gcc libgssapi-krb5-2 libkrb5-dev libsasl2-modules-gssapi-mit
41+
3242
- name: Caching project dependencies
3343
id: project-cache
3444
uses: Swatinem/rust-cache@v2
@@ -49,6 +59,11 @@ jobs:
4959
steps:
5060
- uses: actions/checkout@v3
5161

62+
- name: Make the USER own the working directory. Installing `gssapi` headers
63+
run: |
64+
sudo chown -R $USER:$USER ${{ github.workspace }}
65+
sudo apt -y install gcc libgssapi-krb5-2 libkrb5-dev libsasl2-modules-gssapi-mit
66+
5267
- name: Caching project dependencies
5368
id: project-cache
5469
uses: Swatinem/rust-cache@v2
@@ -57,4 +72,4 @@ jobs:
5772
with:
5873
rust-version: nightly
5974

60-
- run: cargo rustdoc -p ${{ matrix.crate }} --all-features -- -D warnings
75+
- run: cargo rustdoc --target=x86_64-unknown-linux-gnu -p ${{ matrix.crate }} --all-features -- -D warnings

.github/workflows/continuous-integration.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ jobs:
2323
- { rust: stable, os: windows-latest }
2424

2525
steps:
26-
- name: Make the USER own the working directory
26+
- name: Make the USER own the working directory. Installing `gssapi` headers
2727
if: ${{ matrix.os == 'ubuntu-latest' }}
28-
run: sudo chown -R $USER:$USER ${{ github.workspace }}
28+
run: |
29+
sudo chown -R $USER:$USER ${{ github.workspace }}
30+
sudo apt -y install gcc libgssapi-krb5-2 libkrb5-dev libsasl2-modules-gssapi-mit
2931
3032
- uses: actions/checkout@v3
3133

@@ -43,12 +45,16 @@ jobs:
4345

4446
- name: Load data for MSSQL tests
4547
if: ${{ matrix.os == 'ubuntu-latest' }}
46-
run: cargo test initialize_sql_server_docker_instance -p tests --all-features --no-fail-fast -- --show-output --nocapture --include-ignored
48+
run: cargo test initialize_sql_server_docker_instance -p tests --target=x86_64-unknown-linux-gnu --all-features --no-fail-fast -- --show-output --nocapture --include-ignored
4749

4850
- name: Run all tests, UNIT and INTEGRATION for Linux targets
4951
if: ${{ matrix.os == 'ubuntu-latest' }}
5052
run: cargo test --verbose --workspace --all-features --no-fail-fast -- --show-output --test-threads=1
5153

52-
- name: Run only UNIT tests for the rest of the defined targets
53-
if: ${{ matrix.os != 'ubuntu-latest' }}
54+
- name: Run only UNIT tests for Windows
55+
if: ${{ matrix.os == 'windows-latest' }}
56+
run: cargo test --verbose --workspace --target=x86_64-pc-windows-msvc --exclude tests --all-features --no-fail-fast -- --show-output
57+
58+
- name: Run only UNIT tests for MacOS
59+
if: ${{ matrix.os == 'MacOS-latest' }}
5460
run: cargo test --verbose --workspace --exclude tests --all-features --no-fail-fast -- --show-output

bash_aliases.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# This alias avoid the usage of a bunch of commands for performn an integrated task that
55
# depends on several concatenated commands.
66

7-
# In order to run the script, simply type `$ . ./alias.sh` from the root of the project.
7+
# In order to run the script, simply type `$ . ./bash_aliases.sh` from the root of the project.
88
# (refreshing the current terminal session could be required)
99

1010
# Executes the docker compose script to wake up the postgres container

canyon_connection/Cargo.toml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "canyon_connection"
3-
version = "0.1.2"
3+
version = "0.2.0"
44
edition = "2021"
55
documentation = "https://zerodaycode.github.io/canyon-book/"
66
homepage = "https://github.com/zerodaycode/Canyon-SQL"
@@ -16,10 +16,14 @@ tokio-postgres = { version = "0.7.2", features = ["with-chrono-0_4"] }
1616
futures = "0.3.25"
1717
indexmap = "1.9.1"
1818

19-
tiberius = { version = "0.11.3", features = ["tds73", "chrono"] }
19+
tiberius = { version = "0.12.1", features = ["tds73", "chrono", "integrated-auth-gssapi"] }
2020
async-std = { version = "1.12.0" }
2121

2222
lazy_static = "1.4.0"
2323

2424
serde = { version = "1.0.138", features = ["derive"] }
25-
toml = "0.5.9"
25+
toml = "0.7.3"
26+
27+
[features]
28+
mssql-integrated-auth = []
29+

canyon_connection/src/canyon_database_connector.rs

Lines changed: 71 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use serde::Deserialize;
44
use tiberius::{AuthMethod, Config};
55
use tokio_postgres::{Client, NoTls};
66

7-
use crate::datasources::DatasourceProperties;
7+
use crate::datasources::DatasourceConfig;
88

99
/// Represents the current supported databases by Canyon
1010
#[derive(Deserialize, Debug, Eq, PartialEq, Clone, Copy, Default)]
@@ -31,29 +31,38 @@ pub struct SqlServerConnection {
3131
/// starts, Canyon gets the information about the desired datasources,
3232
/// process them and generates a pool of 1 to 1 database connection for
3333
/// every datasource defined.
34-
pub struct DatabaseConnection {
35-
pub postgres_connection: Option<PostgreSqlConnection>,
36-
pub sqlserver_connection: Option<SqlServerConnection>,
37-
pub database_type: DatabaseType,
34+
pub enum DatabaseConnection {
35+
Postgres(PostgreSqlConnection),
36+
SqlServer(SqlServerConnection),
3837
}
3938

4039
unsafe impl Send for DatabaseConnection {}
4140
unsafe impl Sync for DatabaseConnection {}
4241

4342
impl DatabaseConnection {
4443
pub async fn new(
45-
datasource: &DatasourceProperties<'_>,
44+
datasource: &DatasourceConfig,
4645
) -> Result<DatabaseConnection, Box<(dyn std::error::Error + Send + Sync + 'static)>> {
47-
match datasource.db_type {
46+
match datasource.get_db_type() {
4847
DatabaseType::PostgreSql => {
48+
let (username, password) = match &datasource.auth {
49+
crate::datasources::Auth::Postgres(postgres_auth) => match postgres_auth {
50+
crate::datasources::PostgresAuth::Basic { username, password } => {
51+
(username.as_str(), password.as_str())
52+
}
53+
},
54+
crate::datasources::Auth::SqlServer(_) => {
55+
panic!("Found SqlServer auth configuration for a PostgreSQL datasource")
56+
}
57+
};
4958
let (new_client, new_connection) = tokio_postgres::connect(
5059
&format!(
5160
"postgres://{user}:{pswd}@{host}:{port}/{db}",
52-
user = datasource.username,
53-
pswd = datasource.password,
54-
host = datasource.host,
55-
port = datasource.port.unwrap_or_default(),
56-
db = datasource.db_name
61+
user = username,
62+
pswd = password,
63+
host = datasource.properties.host,
64+
port = datasource.properties.port.unwrap_or_default(),
65+
db = datasource.properties.db_name
5766
)[..],
5867
NoTls,
5968
)
@@ -65,27 +74,31 @@ impl DatabaseConnection {
6574
}
6675
});
6776

68-
Ok(Self {
69-
postgres_connection: Some(PostgreSqlConnection {
70-
client: new_client,
71-
// connection: new_connection,
72-
}),
73-
sqlserver_connection: None,
74-
database_type: DatabaseType::PostgreSql,
75-
})
77+
Ok(DatabaseConnection::Postgres(PostgreSqlConnection {
78+
client: new_client,
79+
// connection: new_connection,
80+
}))
7681
}
7782
DatabaseType::SqlServer => {
7883
let mut config = Config::new();
7984

80-
config.host(datasource.host);
81-
config.port(datasource.port.unwrap_or_default());
82-
config.database(datasource.db_name);
85+
config.host(&datasource.properties.host);
86+
config.port(datasource.properties.port.unwrap_or_default());
87+
config.database(&datasource.properties.db_name);
8388

8489
// Using SQL Server authentication.
85-
config.authentication(AuthMethod::sql_server(
86-
datasource.username,
87-
datasource.password,
88-
));
90+
config.authentication(match &datasource.auth {
91+
crate::datasources::Auth::Postgres(_) => {
92+
panic!("Found PostgreSQL auth configuration for a SqlServer database")
93+
}
94+
crate::datasources::Auth::SqlServer(sql_server_auth) => match sql_server_auth {
95+
crate::datasources::SqlServerAuth::Basic { username, password } => {
96+
AuthMethod::sql_server(username, password)
97+
}
98+
#[cfg(feature = "mssql-integrated-auth")]
99+
crate::datasources::SqlServerAuth::Integrated => AuthMethod::Integrated,
100+
},
101+
});
89102

90103
// on production, it is not a good idea to do this. We should upgrade
91104
// Canyon in future versions to allow the user take care about this
@@ -106,18 +119,30 @@ impl DatabaseConnection {
106119
// Handling TLS, login and other details related to the SQL Server.
107120
let client = tiberius::Client::connect(config, tcp).await;
108121

109-
Ok(Self {
110-
postgres_connection: None,
111-
sqlserver_connection: Some(SqlServerConnection {
112-
client: Box::leak(Box::new(
113-
client.expect("A failure happened connecting to the database"),
114-
)),
115-
}),
116-
database_type: DatabaseType::SqlServer,
117-
})
122+
Ok(DatabaseConnection::SqlServer(SqlServerConnection {
123+
client: Box::leak(Box::new(
124+
client.expect("A failure happened connecting to the database"),
125+
)),
126+
}))
118127
}
119128
}
120129
}
130+
131+
pub fn postgres_connection(&self) -> Option<&PostgreSqlConnection> {
132+
if let DatabaseConnection::Postgres(conn) = self {
133+
Some(conn)
134+
} else {
135+
None
136+
}
137+
}
138+
139+
pub fn sqlserver_connection(&mut self) -> Option<&mut SqlServerConnection> {
140+
if let DatabaseConnection::SqlServer(conn) = self {
141+
Some(conn)
142+
} else {
143+
None
144+
}
145+
}
121146
}
122147

123148
#[cfg(test)]
@@ -128,8 +153,8 @@ mod database_connection_handler {
128153
const CONFIG_FILE_MOCK_ALT: &str = r#"
129154
[canyon_sql]
130155
datasources = [
131-
{name = 'PostgresDS', properties.db_type = 'postgresql', properties.username = 'username', properties.password = 'random_pass', properties.host = 'localhost', properties.db_name = 'triforce', properties.migrations='enabled'},
132-
{name = 'SqlServerDS', properties.db_type = 'sqlserver', properties.username = 'username2', properties.password = 'random_pass2', properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled'}
156+
{name = 'PostgresDS', auth = { postgresql = { basic = { username = "postgres", password = "postgres" } } }, properties.host = 'localhost', properties.db_name = 'triforce', properties.migrations='enabled' },
157+
{name = 'SqlServerDS', auth = { sqlserver = { basic = { username = "sa", password = "SqlServer-10" } } }, properties.host = '192.168.0.250.1', properties.port = 3340, properties.db_name = 'triforce2', properties.migrations='disabled' }
133158
]
134159
"#;
135160

@@ -139,10 +164,13 @@ mod database_connection_handler {
139164
let config: CanyonSqlConfig = toml::from_str(CONFIG_FILE_MOCK_ALT)
140165
.expect("A failure happened retrieving the [canyon_sql] section");
141166

142-
let psql_ds = &config.canyon_sql.datasources[0].properties;
143-
let sqls_ds = &config.canyon_sql.datasources[1].properties;
144-
145-
assert_eq!(psql_ds.db_type, DatabaseType::PostgreSql);
146-
assert_eq!(sqls_ds.db_type, DatabaseType::SqlServer);
167+
assert_eq!(
168+
config.canyon_sql.datasources[0].get_db_type(),
169+
DatabaseType::PostgreSql
170+
);
171+
assert_eq!(
172+
config.canyon_sql.datasources[1].get_db_type(),
173+
DatabaseType::SqlServer
174+
);
147175
}
148176
}

0 commit comments

Comments
 (0)