0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2025-07-26 11:04:23 +00:00
Files
libsql/libsql-server/tests/standalone/attach.rs
ad hoc 52d8b8f1c4 Multi-scopes auth & Attach fix (#1076)
* test snapshots

* allow multi-scope auth

* hors-sujet: fix C compile warning

* update jwt and add hashbrown feature

* replace Auth with RequestContext

* extract RequestContext

* fix auth check for multi-scopes

* pass NamespaceName in StmtKind::Attach

* fallback to global auth if key is not set in ns config

* add allow_attach to namespace creation

* return meta store from namespace store

* test attach

* fmt

* review edits
2024-02-26 13:56:20 +00:00

202 lines
6.0 KiB
Rust

use base64::Engine;
use insta::assert_debug_snapshot;
use jsonwebtoken::EncodingKey;
use libsql::Database;
use ring::signature::{Ed25519KeyPair, KeyPair};
use crate::common::{http::Client, net::TurmoilConnector};
use super::make_standalone_server;
fn key_pair() -> (EncodingKey, Ed25519KeyPair) {
let doc = Ed25519KeyPair::generate_pkcs8(&ring::rand::SystemRandom::new()).unwrap();
let encoding_key = EncodingKey::from_ed_der(doc.as_ref());
let pair = Ed25519KeyPair::from_pkcs8(doc.as_ref()).unwrap();
(encoding_key, pair)
}
fn encode<T: serde::Serialize>(claims: &T, key: &EncodingKey) -> String {
let header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::EdDSA);
jsonwebtoken::encode(&header, &claims, key).unwrap()
}
#[test]
fn attach_no_auth() {
let mut sim = turmoil::Builder::new().build();
sim.host("primary", make_standalone_server);
sim.client("test", async {
let client = Client::new();
client
.post(
"http://primary:9090/v1/namespaces/foo/create",
serde_json::json!({}),
)
.await
.unwrap();
client
.post(
"http://primary:9090/v1/namespaces/bar/create",
serde_json::json!({ "allow_attach": true}),
)
.await
.unwrap();
let foo_db =
Database::open_remote_with_connector("http://foo.primary:8080", "", TurmoilConnector)?;
let foo_conn = foo_db.connect().unwrap();
foo_conn
.execute("CREATE TABLE foo_table (x)", ())
.await
.unwrap();
foo_conn
.execute("insert into foo_table values (42)", ())
.await
.unwrap();
let bar_db =
Database::open_remote_with_connector("http://bar.primary:8080", "", TurmoilConnector)?;
let bar_conn = bar_db.connect().unwrap();
bar_conn
.execute("CREATE TABLE bar_table (x)", ())
.await
.unwrap();
bar_conn
.execute("insert into bar_table values (43)", ())
.await
.unwrap();
// fails: foo doesn't allow attach
assert_debug_snapshot!(bar_conn.execute("ATTACH foo as foo", ()).await.unwrap_err());
let txn = foo_conn.transaction().await.unwrap();
txn.execute("ATTACH DATABASE bar as bar", ()).await.unwrap();
let mut rows = txn.query("SELECT * FROM bar.bar_table", ()).await.unwrap();
// succeeds!
assert_debug_snapshot!(rows.next().await);
Ok(())
});
sim.run().unwrap();
}
#[test]
fn attach_auth() {
let mut sim = turmoil::Builder::new().build();
sim.host("primary", make_standalone_server);
sim.client("test", async {
let client = Client::new();
let (enc, pair) = key_pair();
let jwt_key = base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(pair.public_key().as_ref());
assert!(client
.post(
"http://primary:9090/v1/namespaces/foo/create",
serde_json::json!({ "jwt_key": jwt_key })
)
.await
.unwrap()
.status()
.is_success());
assert!(client
.post(
"http://primary:9090/v1/namespaces/bar/create",
serde_json::json!({ "allow_attach": true, "jwt_key": jwt_key })
)
.await
.unwrap()
.status()
.is_success());
let claims = serde_json::json!({
"p": {
"rw": {
"ns": ["bar", "foo"]
}
}
});
let token = encode(&claims, &enc);
let foo_db = Database::open_remote_with_connector(
"http://foo.primary:8080",
&token,
TurmoilConnector,
)?;
let foo_conn = foo_db.connect().unwrap();
foo_conn
.execute("CREATE TABLE foo_table (x)", ())
.await
.unwrap();
foo_conn
.execute("insert into foo_table values (42)", ())
.await
.unwrap();
let bar_db = Database::open_remote_with_connector(
"http://bar.primary:8080",
&token,
TurmoilConnector,
)?;
let bar_conn = bar_db.connect().unwrap();
bar_conn
.execute("CREATE TABLE bar_table (x)", ())
.await
.unwrap();
bar_conn
.execute("insert into bar_table values (43)", ())
.await
.unwrap();
// fails: no perm
assert_debug_snapshot!(bar_conn.execute("ATTACH foo as foo", ()).await.unwrap_err());
let txn = foo_conn.transaction().await.unwrap();
// fails: no perm
assert_debug_snapshot!(txn
.execute("ATTACH DATABASE bar as bar", ())
.await
.unwrap_err());
let claims = serde_json::json!({
"p": {
"roa": {
"ns": ["bar", "foo"]
}
}
});
let token = encode(&claims, &enc);
let foo_db = Database::open_remote_with_connector(
"http://foo.primary:8080",
&token,
TurmoilConnector,
)?;
let foo_conn = foo_db.connect().unwrap();
let bar_db = Database::open_remote_with_connector(
"http://bar.primary:8080",
&token,
TurmoilConnector,
)?;
let bar_conn = bar_db.connect().unwrap();
// fails: namesapce doesn't allow attach
assert_debug_snapshot!(bar_conn.execute("ATTACH foo as foo", ()).await.unwrap_err());
let txn = foo_conn.transaction().await.unwrap();
txn.execute("ATTACH DATABASE bar as bar", ()).await.unwrap();
let mut rows = txn.query("SELECT * FROM bar.bar_table", ()).await.unwrap();
// succeeds!
assert_debug_snapshot!(rows.next().await);
Ok(())
});
sim.run().unwrap();
}