20221022 improve test macros (#1139)

This commit is contained in:
Firstyear 2022-10-24 09:50:31 +10:00 committed by GitHub
parent 17774cb3bb
commit c4ecdf4447
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 2577 additions and 2415 deletions

52
Cargo.lock generated
View file

@ -2274,24 +2274,19 @@ dependencies = [
name = "kanidmd_core"
version = "1.1.0-alpha.9"
dependencies = [
"async-std",
"async-trait",
"chrono",
"compact_jwt",
"futures",
"futures-util",
"http-types",
"kanidm_client",
"kanidm_proto",
"kanidmd_lib",
"ldap3_proto",
"libc",
"oauth2",
"openssl",
"profiles",
"rand 0.8.5",
"regex",
"reqwest",
"saffron",
"serde",
"serde_json",
@ -2304,9 +2299,7 @@ dependencies = [
"tokio-openssl",
"tokio-util",
"tracing",
"url",
"uuid",
"webauthn-authenticator-rs",
]
[[package]]
@ -2329,6 +2322,7 @@ dependencies = [
"hex",
"idlset",
"kanidm_proto",
"kanidmd_lib_macros",
"lazy_static",
"ldap3_proto",
"libc",
@ -2367,6 +2361,37 @@ dependencies = [
"zxcvbn",
]
[[package]]
name = "kanidmd_lib_macros"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "kanidmd_testkit"
version = "1.1.0-alpha.9"
dependencies = [
"compact_jwt",
"futures",
"kanidm_client",
"kanidm_proto",
"kanidmd_core",
"kanidmd_lib",
"oauth2",
"profiles",
"reqwest",
"serde_json",
"sketching",
"testkit-macros",
"tokio",
"tracing",
"url",
"webauthn-authenticator-rs",
]
[[package]]
name = "kanidmd_web_ui"
version = "1.1.0-alpha.9"
@ -3582,9 +3607,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.20.6"
version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c"
dependencies = [
"log",
"ring",
@ -4157,6 +4182,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "testkit-macros"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "textwrap"
version = "0.15.1"

View file

@ -14,7 +14,10 @@ members = [
"kanidmd_web_ui",
"kanidmd/daemon",
"kanidmd/lib",
"kanidmd/lib-macros",
"kanidmd/core",
"kanidmd/testkit",
"kanidmd/testkit-macros",
"orca",
"profiles",
"sketching"
@ -72,6 +75,8 @@ js-sys = "^0.3.58"
kanidmd_core = { path = "./kanidmd/core" }
kanidmd_idm = { path = "./kanidmd/idm" }
kanidmd_lib = { path = "./kanidmd/lib" }
kanidmd_lib_macros = { path = "./kanidmd/lib-macros" }
kanidmd_testkit = { path = "./kanidmd/testkit" }
kanidm_client = { path = "./kanidm_client" }
kanidm_proto = { path = "./kanidm_proto" }
kanidm_unix_int = { path = "./kanidm_unix_int" }
@ -89,8 +94,10 @@ oauth2_ext = { version = "^4.1.0", package = "oauth2" }
openssl = "^0.10.41"
paste = "^1.0.9"
pkg-config = "^0.3.25"
proc-macro2 = "1.0.7"
profiles = { path = "./profiles" }
qrcode = "^0.12.0"
quote = "1"
r2d2 = "^0.8.9"
r2d2_sqlite = "^0.21.0"
rand = "^0.8.5"
@ -108,12 +115,12 @@ sketching = { path = "./sketching" }
smartstring = "^1.0.1"
smolset = "^1.3.1"
sshkeys = "^0.3.1"
syn = { version = "1.0.56", features = ["full"] }
testkit-macros = { path = "./kanidmd/testkit-macros" }
tide = "^0.16.0"
# Including brotli *very* slow, so don't do that. Including the "default" feature pulls a mime-type list from the internet on build, which isn't used.
tide-compress = { version="0.10.6", default-features = false, features = [ "gzip", "regex-check" ] }
tide-openssl = "^0.1.1"
# Unable to increase version due to removing ability to detect
# local platform time.
time = "=0.2.27"

View file

@ -2,6 +2,7 @@
name = "kanidmd_core"
description = "Kanidm Server Core and Library"
documentation = "https://docs.rs/kanidm/latest/kanidm/"
autotests = false
version.workspace = true
authors.workspace = true
@ -12,7 +13,6 @@ homepage.workspace = true
repository.workspace = true
[dependencies]
async-std = { workspace = true, features = ["tokio1"] }
async-trait.workspace = true
chrono.workspace = true
compact_jwt.workspace = true
@ -41,13 +41,3 @@ uuid = { workspace = true, features = ["serde", "v4" ] }
[build-dependencies]
profiles.workspace = true
[dev-dependencies]
kanidm_client.workspace = true
futures.workspace = true
webauthn-authenticator-rs.workspace = true
oauth2_ext = { workspace = true, default-features = false }
url = { workspace = true, features = ["serde"] }
reqwest = { workspace = true, features=["cookies", "json", "native-tls"] }

View file

@ -77,7 +77,7 @@ impl QueryServerReadV1 {
) -> Result<SearchResponse, OperationError> {
// Begin a read
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -173,7 +173,7 @@ impl QueryServerReadV1 {
// Scope to limit the read txn.
{
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
idms_prox_read
.qs_read
.get_be_txn()
@ -286,7 +286,7 @@ impl QueryServerReadV1 {
// TODO #62: Move this to IdmServer!!!
// Begin a read
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
// Make an event from the whoami request. This will process the event and
// generate a selfuuid search.
//
@ -333,7 +333,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Vec<ProtoEntry>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -376,7 +376,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Vec<ProtoEntry>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -419,7 +419,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Option<String>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -479,7 +479,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<RadiusAuthToken, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_read = self.idms.proxy_read_async().await;
let mut idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -526,7 +526,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<UnixUserToken, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_read = self.idms.proxy_read_async().await;
let mut idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -573,7 +573,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<UnixGroupToken, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_read = self.idms.proxy_read_async().await;
let mut idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -619,7 +619,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Vec<String>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -682,7 +682,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Option<String>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -746,7 +746,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Vec<ApiToken>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -778,7 +778,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Vec<UatStatus>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -860,7 +860,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<CredentialStatus, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_read = self.idms.proxy_read_async().await;
let mut idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -906,7 +906,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<BackupCodesView, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_read = self.idms.proxy_read_async().await;
let mut idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -1112,7 +1112,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Option<String>, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let ident = idms_prox_read
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -1162,7 +1162,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<AuthoriseResponse, Oauth2Error> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let (ident, uat) = idms_prox_read
.validate_and_parse_uat(uat.as_deref(), ct)
.and_then(|uat| {
@ -1191,7 +1191,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<AuthorisePermitSuccess, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let (ident, uat) = idms_prox_read
.validate_and_parse_uat(uat.as_deref(), ct)
.and_then(|uat| {
@ -1219,7 +1219,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<Url, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
let (ident, uat) = idms_prox_read
.validate_and_parse_uat(uat.as_deref(), ct)
.and_then(|uat| {
@ -1247,7 +1247,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<AccessTokenResponse, Oauth2Error> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
// Now we can send to the idm server for authorisation checking.
idms_prox_read.check_oauth2_token_exchange(client_authz.as_deref(), &token_req, ct)
}
@ -1264,7 +1264,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<AccessTokenIntrospectResponse, Oauth2Error> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
// Now we can send to the idm server for introspection checking.
idms_prox_read.check_oauth2_token_introspect(&client_authz, &intr_req, ct)
}
@ -1281,7 +1281,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<OidcToken, Oauth2Error> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
idms_prox_read.oauth2_openid_userinfo(&client_id, &client_authz, ct)
}
@ -1295,7 +1295,7 @@ impl QueryServerReadV1 {
client_id: String,
eventid: Uuid,
) -> Result<OidcDiscoveryResponse, OperationError> {
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
idms_prox_read.oauth2_openid_discovery(&client_id)
}
@ -1309,7 +1309,7 @@ impl QueryServerReadV1 {
client_id: String,
eventid: Uuid,
) -> Result<JwkKeySet, OperationError> {
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
idms_prox_read.oauth2_openid_publickey(&client_id)
}
@ -1319,7 +1319,7 @@ impl QueryServerReadV1 {
fields(uuid = ?eventid)
)]
pub async fn get_domain_display_name(&self, eventid: Uuid) -> String {
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
idms_prox_read.qs_read.get_domain_display_name().to_string()
}
@ -1334,7 +1334,7 @@ impl QueryServerReadV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_read = self.idms.proxy_read_async().await;
let idms_prox_read = self.idms.proxy_read().await;
idms_prox_read
.validate_and_parse_uat(uat.as_deref(), ct)

View file

@ -58,7 +58,7 @@ impl QueryServerWriteV1 {
proto_ml: &ProtoModifyList,
filter: Filter<FilterInvalid>,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -106,7 +106,7 @@ impl QueryServerWriteV1 {
ml: &ModifyList<ModifyInvalid>,
filter: Filter<FilterInvalid>,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -160,7 +160,7 @@ impl QueryServerWriteV1 {
req: CreateRequest,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -197,7 +197,7 @@ impl QueryServerWriteV1 {
req: ModifyRequest,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -233,7 +233,7 @@ impl QueryServerWriteV1 {
req: DeleteRequest,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -270,7 +270,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
// Given a protoEntry, turn this into a modification set.
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -311,7 +311,7 @@ impl QueryServerWriteV1 {
filter: Filter<FilterInvalid>,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -346,7 +346,7 @@ impl QueryServerWriteV1 {
filter: Filter<FilterInvalid>,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -382,7 +382,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<String, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -430,7 +430,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<String, OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -472,7 +472,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -512,7 +512,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -550,7 +550,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
// We specifically need a uat here to assess the auth type!
let (ident, uat) = idms_prox_write
@ -596,7 +596,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(CUSessionToken, CUStatus), OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -645,7 +645,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<CUIntentToken, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -690,7 +690,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(CUSessionToken, CUStatus), OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let intent_token = CredentialUpdateIntentToken {
intent_id: intent_token.token,
};
@ -726,7 +726,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let session_token = CredentialUpdateSessionToken {
token_enc: session_token.token,
};
@ -754,7 +754,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let session_token = CredentialUpdateSessionToken {
token_enc: session_token.token,
};
@ -783,7 +783,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -815,7 +815,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<String, OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -863,7 +863,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -914,7 +914,7 @@ impl QueryServerWriteV1 {
filter: Filter<FilterInvalid>,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
@ -1130,7 +1130,7 @@ impl QueryServerWriteV1 {
eventid: Uuid,
) -> Result<(), OperationError> {
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
let ident = idms_prox_write
.validate_and_parse_token_to_ident(uat.as_deref(), ct)
.map_err(|e| {
@ -1179,7 +1179,7 @@ impl QueryServerWriteV1 {
) -> Result<(), OperationError> {
// Because this is from internal, we can generate a real modlist, rather
// than relying on the proto ones.
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -1237,7 +1237,7 @@ impl QueryServerWriteV1 {
filter: Filter<FilterInvalid>,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -1293,7 +1293,7 @@ impl QueryServerWriteV1 {
) -> Result<(), OperationError> {
// Because this is from internal, we can generate a real modlist, rather
// than relying on the proto ones.
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -1351,7 +1351,7 @@ impl QueryServerWriteV1 {
filter: Filter<FilterInvalid>,
eventid: Uuid,
) -> Result<(), OperationError> {
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let mut idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let ct = duration_from_epoch_now();
let ident = idms_prox_write
@ -1400,7 +1400,7 @@ impl QueryServerWriteV1 {
)]
pub async fn handle_purgetombstoneevent(&self, msg: PurgeTombstoneEvent) {
trace!(?msg, "Begin purge tombstone event");
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let res = idms_prox_write
.qs_write
@ -1418,7 +1418,7 @@ impl QueryServerWriteV1 {
)]
pub async fn handle_purgerecycledevent(&self, msg: PurgeRecycledEvent) {
trace!(?msg, "Begin purge recycled event");
let idms_prox_write = self.idms.proxy_write_async(duration_from_epoch_now()).await;
let idms_prox_write = self.idms.proxy_write(duration_from_epoch_now()).await;
let res = idms_prox_write
.qs_write
.purge_recycled()
@ -1435,7 +1435,7 @@ impl QueryServerWriteV1 {
trace!("Begin delayed action ...");
let ct = duration_from_epoch_now();
let mut idms_prox_write = self.idms.proxy_write_async(ct).await;
let mut idms_prox_write = self.idms.proxy_write(ct).await;
if let Err(res) = idms_prox_write
.process_delayedaction(da)
.and_then(|_| idms_prox_write.commit())

View file

@ -1,7 +1,6 @@
use std::str::FromStr;
use std::time::Duration;
use async_std::task;
use compact_jwt::Jws;
use kanidm_proto::v1::{
AccountUnixExtend, ApiTokenGenerate, AuthRequest, AuthResponse, AuthState as ProtoAuthState,
@ -1068,12 +1067,8 @@ pub async fn auth(mut req: tide::Request<AppState>) -> tide::Result {
let AuthResult {
state,
sessionid,
delay,
delay: _,
} = ar;
// If there is a delay, honour it now.
if let Some(delay_timer) = delay {
task::sleep(delay_timer).await;
}
// Do some response/state management.
match state {
AuthState::Choose(allowed) => {

View file

@ -34,7 +34,6 @@ mod ldaps;
use std::sync::Arc;
use async_std::task;
use compact_jwt::JwsSigner;
use kanidm_proto::messages::{AccountChangeMessage, MessageStatus};
use kanidm_proto::v1::OperationError;
@ -96,7 +95,7 @@ fn setup_backend_vacuum(
// outside of this call, then pass in "what we need" in a cloneable
// form, this way we could have seperate Idm vs Qs threads, and dedicated
// threads for write vs read
fn setup_qs_idms(
async fn setup_qs_idms(
be: Backend,
schema: Schema,
config: &Configuration,
@ -112,7 +111,9 @@ fn setup_qs_idms(
// Now search for the schema itself, and validate that the system
// in memory matches the BE on disk, and that it's syntactically correct.
// Write it out if changes are needed.
query_server.initialise_helper(duration_from_epoch_now())?;
query_server
.initialise_helper(duration_from_epoch_now())
.await?;
// We generate a SINGLE idms only!
@ -121,7 +122,7 @@ fn setup_qs_idms(
Ok((query_server, idms, idms_delayed))
}
fn setup_qs(
async fn setup_qs(
be: Backend,
schema: Schema,
config: &Configuration,
@ -137,7 +138,9 @@ fn setup_qs(
// Now search for the schema itself, and validate that the system
// in memory matches the BE on disk, and that it's syntactically correct.
// Write it out if changes are needed.
query_server.initialise_helper(duration_from_epoch_now())?;
query_server
.initialise_helper(duration_from_epoch_now())
.await?;
Ok(query_server)
}
@ -261,7 +264,7 @@ pub fn backup_server_core(config: &Configuration, dst_path: &str) {
// Let the txn abort, even on success.
}
pub fn restore_server_core(config: &Configuration, dst_path: &str) {
pub async fn restore_server_core(config: &Configuration, dst_path: &str) {
touch_file_or_quit(config.db_path.as_str());
// First, we provide the in-memory schema so that core attrs are indexed correctly.
@ -292,7 +295,7 @@ pub fn restore_server_core(config: &Configuration, dst_path: &str) {
info!("Attempting to init query server ...");
let (qs, _idms, _idms_delayed) = match setup_qs_idms(be, schema, config) {
let (qs, _idms, _idms_delayed) = match setup_qs_idms(be, schema, config).await {
Ok(t) => t,
Err(e) => {
error!("Unable to setup query server or idm server -> {:?}", e);
@ -303,7 +306,7 @@ pub fn restore_server_core(config: &Configuration, dst_path: &str) {
info!("Start reindex phase ...");
let qs_write = task::block_on(qs.write_async(duration_from_epoch_now()));
let qs_write = qs.write(duration_from_epoch_now()).await;
let r = qs_write.reindex().and_then(|_| qs_write.commit());
match r {
@ -317,7 +320,7 @@ pub fn restore_server_core(config: &Configuration, dst_path: &str) {
info!("✅ Restore Success!");
}
pub fn reindex_server_core(config: &Configuration) {
pub async fn reindex_server_core(config: &Configuration) {
eprintln!("Start Index Phase 1 ...");
// First, we provide the in-memory schema so that core attrs are indexed correctly.
let schema = match Schema::new() {
@ -349,7 +352,7 @@ pub fn reindex_server_core(config: &Configuration) {
eprintln!("Attempting to init query server ...");
let (qs, _idms, _idms_delayed) = match setup_qs_idms(be, schema, config) {
let (qs, _idms, _idms_delayed) = match setup_qs_idms(be, schema, config).await {
Ok(t) => t,
Err(e) => {
error!("Unable to setup query server or idm server -> {:?}", e);
@ -360,7 +363,7 @@ pub fn reindex_server_core(config: &Configuration) {
eprintln!("Start Index Phase 2 ...");
let qs_write = task::block_on(qs.write_async(duration_from_epoch_now()));
let qs_write = qs.write(duration_from_epoch_now()).await;
let r = qs_write.reindex().and_then(|_| qs_write.commit());
match r {
@ -394,7 +397,7 @@ pub fn vacuum_server_core(config: &Configuration) {
};
}
pub fn domain_rename_core(config: &Configuration) {
pub async fn domain_rename_core(config: &Configuration) {
let schema = match Schema::new() {
Ok(s) => s,
Err(e) => {
@ -413,7 +416,7 @@ pub fn domain_rename_core(config: &Configuration) {
};
// Setup the qs, and perform any migrations and changes we may have.
let qs = match setup_qs(be, schema, config) {
let qs = match setup_qs(be, schema, config).await {
Ok(t) => t,
Err(e) => {
error!("Unable to setup query server -> {:?}", e);
@ -424,7 +427,7 @@ pub fn domain_rename_core(config: &Configuration) {
let new_domain_name = config.domain.as_str();
// make sure we're actually changing the domain name...
match task::block_on(qs.read_async()).get_db_domain_name() {
match qs.read().await.get_db_domain_name() {
Ok(old_domain_name) => {
admin_info!(?old_domain_name, ?new_domain_name);
if &old_domain_name == &new_domain_name {
@ -443,7 +446,7 @@ pub fn domain_rename_core(config: &Configuration) {
}
}
let qs_write = task::block_on(qs.write_async(duration_from_epoch_now()));
let mut qs_write = qs.write(duration_from_epoch_now()).await;
let r = qs_write
.domain_rename(new_domain_name)
.and_then(|_| qs_write.commit());
@ -457,7 +460,7 @@ pub fn domain_rename_core(config: &Configuration) {
};
}
pub fn verify_server_core(config: &Configuration) {
pub async fn verify_server_core(config: &Configuration) {
// setup the qs - without initialise!
let schema_mem = match Schema::new() {
Ok(sc) => sc,
@ -477,7 +480,7 @@ pub fn verify_server_core(config: &Configuration) {
let server = QueryServer::new(be, schema_mem, config.domain.clone());
// Run verifications.
let r = server.verify();
let r = server.verify().await;
if r.is_empty() {
eprintln!("Verification passed!");
@ -492,7 +495,7 @@ pub fn verify_server_core(config: &Configuration) {
// Now add IDM server verifications?
}
pub fn recover_account_core(config: &Configuration, name: &str) {
pub async fn recover_account_core(config: &Configuration, name: &str) {
let schema = match Schema::new() {
Ok(s) => s,
Err(e) => {
@ -510,7 +513,7 @@ pub fn recover_account_core(config: &Configuration, name: &str) {
}
};
// setup the qs - *with* init of the migrations and schema.
let (_qs, idms, _idms_delayed) = match setup_qs_idms(be, schema, config) {
let (_qs, idms, _idms_delayed) = match setup_qs_idms(be, schema, config).await {
Ok(t) => t,
Err(e) => {
error!("Unable to setup query server or idm server -> {:?}", e);
@ -519,7 +522,7 @@ pub fn recover_account_core(config: &Configuration, name: &str) {
};
// Run the password change.
let mut idms_prox_write = task::block_on(idms.proxy_write_async(duration_from_epoch_now()));
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
let new_pw = match idms_prox_write.recover_account(name, None) {
Ok(new_pw) => match idms_prox_write.commit() {
Ok(_) => new_pw,
@ -601,7 +604,7 @@ pub async fn create_server_core(config: Configuration, config_test: bool) -> Res
}
};
// Start the IDM server.
let (_qs, idms, mut idms_delayed) = match setup_qs_idms(be, schema, &config) {
let (_qs, idms, mut idms_delayed) = match setup_qs_idms(be, schema, &config).await {
Ok(t) => t,
Err(e) => {
error!("Unable to setup query server or idm server -> {:?}", e);
@ -622,8 +625,7 @@ pub async fn create_server_core(config: Configuration, config_test: bool) -> Res
// Any pre-start tasks here.
match &config.integration_test_config {
Some(itc) => {
let mut idms_prox_write =
task::block_on(idms.proxy_write_async(duration_from_epoch_now()));
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
match idms_prox_write.recover_account("admin", Some(&itc.admin_password)) {
Ok(_) => {}
Err(e) => {

View file

@ -1,80 +0,0 @@
use std::sync::atomic::Ordering;
mod common;
use kanidmd_core::config::{Configuration, IntegrationTestConfig, ServerRole};
use kanidmd_core::create_server_core;
use tokio::task;
use crate::common::{is_free_port, ADMIN_TEST_PASSWORD, ADMIN_TEST_USER, PORT_ALLOC};
#[tokio::test]
async fn test_https_middleware_headers() {
// tests stuff
let _ = sketching::test_init();
let mut counter = 0;
let port = loop {
let possible_port = PORT_ALLOC.fetch_add(1, Ordering::SeqCst);
if is_free_port(possible_port) {
break possible_port;
}
counter += 1;
if counter >= 5 {
eprintln!("Unable to allocate port!");
assert!(false);
}
};
let int_config = Box::new(IntegrationTestConfig {
admin_user: ADMIN_TEST_USER.to_string(),
admin_password: ADMIN_TEST_PASSWORD.to_string(),
});
// Setup the config ...
let mut config = Configuration::new();
config.address = format!("127.0.0.1:{}", port);
config.secure_cookies = false;
config.integration_test_config = Some(int_config);
config.role = ServerRole::WriteReplica;
config.threads = 1;
create_server_core(config, false)
.await
.expect("failed to start server core");
// We have to yield now to guarantee that the tide elements are setup.
task::yield_now().await;
let addr = format!("http://127.0.0.1:{}/", port);
// here we test the /ui/ endpoint which should have the headers
let response = match reqwest::get(format!("{}ui/", &addr)).await {
Ok(value) => value,
Err(error) => {
panic!("Failed to query {:?} : {:#?}", addr, error);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 200);
eprintln!(
"csp headers: {:#?}",
response.headers().get("content-security-policy")
);
assert_ne!(response.headers().get("content-security-policy"), None);
// here we test the /pkg/ endpoint which shouldn't have the headers
let response =
match reqwest::get(format!("{}pkg/external/bootstrap.bundle.min.js", &addr)).await {
Ok(value) => value,
Err(error) => {
panic!("Failed to query {:?} : {:#?}", addr, error);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 200);
eprintln!(
"csp headers: {:#?}",
response.headers().get("content-security-policy")
);
assert_eq!(response.headers().get("content-security-policy"), None);
}

View file

@ -374,23 +374,23 @@ async fn main() {
std::process::exit(1);
}
};
restore_server_core(&config, p);
restore_server_core(&config, p).await;
}
KanidmdOpt::Database {
commands: DbCommands::Verify(_vopt),
} => {
eprintln!("Running in db verification mode ...");
verify_server_core(&config);
verify_server_core(&config).await;
}
KanidmdOpt::RecoverAccount(raopt) => {
eprintln!("Running account recovery ...");
recover_account_core(&config, &raopt.name);
recover_account_core(&config, &raopt.name).await;
}
KanidmdOpt::Database {
commands: DbCommands::Reindex(_copt),
} => {
eprintln!("Running in reindex mode ...");
reindex_server_core(&config);
reindex_server_core(&config).await;
}
KanidmdOpt::DbScan {
commands: DbScanOpt::ListIndexes(_),
@ -426,7 +426,7 @@ async fn main() {
commands: DomainSettingsCmds::DomainChange(_dopt),
} => {
eprintln!("Running in domain name change mode ... this may take a long time ...");
domain_rename_core(&config);
domain_rename_core(&config).await;
}
KanidmdOpt::Database {
commands: DbCommands::Vacuum(_copt),

View file

@ -0,0 +1,13 @@
[package]
name = "kanidmd_lib_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
proc-macro2.workspace = true
quote.workspace = true
syn.workspace = true

View file

@ -0,0 +1,99 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::{quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
tokens.extend(TokenStream::from(error.into_compile_error()));
tokens
}
pub(crate) fn qs_test(_args: TokenStream, item: TokenStream, with_init: bool) -> TokenStream {
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) {
let msg = "second test attribute is supplied";
return token_stream_with_error(item, syn::Error::new_spanned(&attr, msg));
};
if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return token_stream_with_error(item, syn::Error::new_spanned(input.sig.fn_token, msg));
}
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, _last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let rt = quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
};
let header = quote! {
#[::core::prelude::v1::test]
};
let init = if with_init {
quote! {
test_server.initialise_helper(duration_from_epoch_now())
.await
.expect("init failed!");
}
} else {
quote! {}
};
let test_fn = &input.sig.ident;
let test_driver = Ident::new(&format!("qs_{}", test_fn), input.sig.span());
// Effectively we are just injecting a real test function around this which we will
// call.
let result = quote! {
#input
#header
fn #test_driver() {
let body = async {
let test_server = crate::testkit::setup_test().await;
#init
#test_fn(&test_server).await;
// Any needed teardown?
// Make sure there are no errors.
let verifications = test_server.verify().await;
trace!("Verification result: {:?}", verifications);
assert!(verifications.len() == 0);
};
#[allow(clippy::expect_used, clippy::diverging_sub_expression)]
{
return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body);
}
}
};
result.into()
}

View file

@ -0,0 +1,28 @@
#![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
mod entry;
#[allow(unused_extern_crates)]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn qs_test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::qs_test(args, item, true)
}
#[proc_macro_attribute]
pub fn qs_test_no_init(args: TokenStream, item: TokenStream) -> TokenStream {
entry::qs_test(args, item, false)
}

View file

@ -35,6 +35,7 @@ hashbrown.workspace = true
hex.workspace = true
idlset.workspace = true
kanidm_proto.workspace = true
kanidmd_lib_macros.workspace = true
lazy_static.workspace = true
ldap3_proto.workspace = true
libc.workspace = true

View file

@ -1571,46 +1571,45 @@ mod tests {
}};
}
#[test]
fn test_access_acp_parser() {
run_test!(|qs: &QueryServer| {
// Test parsing entries to acp. There so no point testing schema violations
// because the schema system is well tested an robust. Instead we target
// entry misconfigurations, such as missing classes required.
#[qs_test]
async fn test_access_acp_parser(qs: &QueryServer) {
// Test parsing entries to acp. There so no point testing schema violations
// because the schema system is well tested an robust. Instead we target
// entry misconfigurations, such as missing classes required.
// Generally, we are testing the *positive* cases here, because schema
// really protects us *a lot* here, but it's nice to have defence and
// layers of validation.
// Generally, we are testing the *positive* cases here, because schema
// really protects us *a lot* here, but it's nice to have defence and
// layers of validation.
let mut qs_write = qs.write(duration_from_epoch_now());
let mut qs_write = qs.write(duration_from_epoch_now()).await;
acp_from_entry_err!(
&mut qs_write,
r#"{
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object"],
"name": ["acp_invalid"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"]
}
}"#,
AccessControlProfile
);
AccessControlProfile
);
acp_from_entry_err!(
&mut qs_write,
r#"{
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_invalid"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"]
}
}"#,
AccessControlProfile
);
AccessControlProfile
);
acp_from_entry_err!(
&mut qs_write,
r#"{
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_invalid"],
@ -1619,42 +1618,40 @@ mod tests {
"acp_targetscope": [""]
}
}"#,
AccessControlProfile
);
AccessControlProfile
);
// "\"Self\""
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
// "\"Self\""
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
AccessControlProfile
);
})
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
),
AccessControlProfile
);
}
#[test]
fn test_access_acp_delete_parser() {
run_test!(|qs: &QueryServer| {
let mut qs_write = qs.write(duration_from_epoch_now());
#[qs_test]
async fn test_access_acp_delete_parser(qs: &QueryServer) {
let mut qs_write = qs.write(duration_from_epoch_now()).await;
acp_from_entry_err!(
&mut qs_write,
r#"{
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_valid"],
@ -1667,44 +1664,42 @@ mod tests {
]
}
}"#,
AccessControlDelete
);
AccessControlDelete
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_delete")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_delete")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
AccessControlDelete
);
})
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
),
AccessControlDelete
);
}
#[test]
fn test_access_acp_search_parser() {
run_test!(|qs: &QueryServer| {
// Test that parsing search access controls works.
let mut qs_write = qs.write(duration_from_epoch_now());
#[qs_test]
async fn test_access_acp_search_parser(qs: &QueryServer) {
// Test that parsing search access controls works.
let mut qs_write = qs.write(duration_from_epoch_now()).await;
// Missing class acp
acp_from_entry_err!(
&mut qs_write,
r#"{
// Missing class acp
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_search"],
"name": ["acp_invalid"],
@ -1718,13 +1713,13 @@ mod tests {
"acp_search_attr": ["name", "class"]
}
}"#,
AccessControlSearch
);
AccessControlSearch
);
// Missing class acs
acp_from_entry_err!(
&mut qs_write,
r#"{
// Missing class acs
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_invalid"],
@ -1738,13 +1733,13 @@ mod tests {
"acp_search_attr": ["name", "class"]
}
}"#,
AccessControlSearch
);
AccessControlSearch
);
// Missing attr acp_search_attr
acp_from_entry_err!(
&mut qs_write,
r#"{
// Missing attr acp_search_attr
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile", "access_control_search"],
"name": ["acp_invalid"],
@ -1757,206 +1752,15 @@ mod tests {
]
}
}"#,
AccessControlSearch
);
AccessControlSearch
);
// All good!
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_search")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_search_attr", Value::new_iutf8("name")),
("acp_search_attr", Value::new_iutf8("class"))
),
AccessControlSearch
);
})
}
#[test]
fn test_access_acp_modify_parser() {
run_test!(|qs: &QueryServer| {
// Test that parsing modify access controls works.
let mut qs_write = qs.write(duration_from_epoch_now());
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_valid"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"],
"acp_receiver": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_targetscope": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_modify_removedattr": ["name"],
"acp_modify_presentattr": ["name"],
"acp_modify_class": ["object"]
}
}"#,
AccessControlModify
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_modify")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
),
AccessControlModify
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_modify")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_modify_removedattr", Value::new_iutf8("name")),
("acp_modify_presentattr", Value::new_iutf8("name")),
("acp_modify_class", Value::new_iutf8("object"))
),
AccessControlModify
);
})
}
#[test]
fn test_access_acp_create_parser() {
run_test!(|qs: &QueryServer| {
// Test that parsing create access controls works.
let mut qs_write = qs.write(duration_from_epoch_now());
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_valid"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"],
"acp_receiver": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_targetscope": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_create_class": ["object"],
"acp_create_attr": ["name"]
}
}"#,
AccessControlCreate
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_create")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
),
AccessControlCreate
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_create")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_create_attr", Value::new_iutf8("name")),
("acp_create_class", Value::new_iutf8("object"))
),
AccessControlCreate
);
})
}
#[test]
fn test_access_acp_compound_parser() {
run_test!(|qs: &QueryServer| {
// Test that parsing compound access controls works. This means that
// given a single &str, we can evaluate all types from a single record.
// This is valid, and could exist, IE a rule to allow create, search and modify
// over a single scope.
let mut qs_write = qs.write(duration_from_epoch_now());
let e = entry_init!(
// All good!
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_create")),
("class", Value::new_class("access_control_delete")),
("class", Value::new_class("access_control_modify")),
("class", Value::new_class("access_control_search")),
("name", Value::new_iname("acp_valid")),
(
@ -1972,18 +1776,202 @@ mod tests {
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_search_attr", Value::new_iutf8("name")),
("acp_create_class", Value::new_iutf8("class")),
("acp_create_attr", Value::new_iutf8("name")),
("acp_search_attr", Value::new_iutf8("class"))
),
AccessControlSearch
);
}
#[qs_test]
async fn test_access_acp_modify_parser(qs: &QueryServer) {
// Test that parsing modify access controls works.
let mut qs_write = qs.write(duration_from_epoch_now()).await;
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_valid"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"],
"acp_receiver": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_targetscope": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_modify_removedattr": ["name"],
"acp_modify_presentattr": ["name"],
"acp_modify_class": ["object"]
}
}"#,
AccessControlModify
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_modify")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
),
AccessControlModify
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_modify")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_modify_removedattr", Value::new_iutf8("name")),
("acp_modify_presentattr", Value::new_iutf8("name")),
("acp_modify_class", Value::new_iutf8("object"))
);
),
AccessControlModify
);
}
acp_from_entry_ok!(&mut qs_write, e.clone(), AccessControlCreate);
acp_from_entry_ok!(&mut qs_write, e.clone(), AccessControlDelete);
acp_from_entry_ok!(&mut qs_write, e.clone(), AccessControlModify);
acp_from_entry_ok!(&mut qs_write, e, AccessControlSearch);
})
#[qs_test]
async fn test_access_acp_create_parser(qs: &QueryServer) {
// Test that parsing create access controls works.
let mut qs_write = qs.write(duration_from_epoch_now()).await;
acp_from_entry_err!(
&mut qs_write,
r#"{
"attrs": {
"class": ["object", "access_control_profile"],
"name": ["acp_valid"],
"uuid": ["cc8e95b4-c24f-4d68-ba54-8bed76f63930"],
"acp_receiver": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_targetscope": [
"{\"eq\":[\"name\",\"a\"]}"
],
"acp_create_class": ["object"],
"acp_create_attr": ["name"]
}
}"#,
AccessControlCreate
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_create")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
)
),
AccessControlCreate
);
acp_from_entry_ok!(
&mut qs_write,
entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_create")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_create_attr", Value::new_iutf8("name")),
("acp_create_class", Value::new_iutf8("object"))
),
AccessControlCreate
);
}
#[qs_test]
async fn test_access_acp_compound_parser(qs: &QueryServer) {
// Test that parsing compound access controls works. This means that
// given a single &str, we can evaluate all types from a single record.
// This is valid, and could exist, IE a rule to allow create, search and modify
// over a single scope.
let mut qs_write = qs.write(duration_from_epoch_now()).await;
let e = entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("access_control_profile")),
("class", Value::new_class("access_control_create")),
("class", Value::new_class("access_control_delete")),
("class", Value::new_class("access_control_modify")),
("class", Value::new_class("access_control_search")),
("name", Value::new_iname("acp_valid")),
(
"uuid",
Value::new_uuids("cc8e95b4-c24f-4d68-ba54-8bed76f63930").expect("uuid")
),
(
"acp_receiver",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
(
"acp_targetscope",
Value::new_json_filter_s("{\"eq\":[\"name\",\"a\"]}").expect("filter")
),
("acp_search_attr", Value::new_iutf8("name")),
("acp_create_class", Value::new_iutf8("class")),
("acp_create_attr", Value::new_iutf8("name")),
("acp_modify_removedattr", Value::new_iutf8("name")),
("acp_modify_presentattr", Value::new_iutf8("name")),
("acp_modify_class", Value::new_iutf8("object"))
);
acp_from_entry_ok!(&mut qs_write, e.clone(), AccessControlCreate);
acp_from_entry_ok!(&mut qs_write, e.clone(), AccessControlDelete);
acp_from_entry_ok!(&mut qs_write, e.clone(), AccessControlModify);
acp_from_entry_ok!(&mut qs_write, e, AccessControlSearch);
}
macro_rules! test_acp_search {

View file

@ -1786,16 +1786,15 @@ mod tests {
assert!(f_t2a.get_attr_set() == f_expect);
}
#[test]
fn test_filter_resolve_value() {
run_test!(|server: &QueryServer| {
let time_p1 = duration_from_epoch_now();
let time_p2 = time_p1 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
let time_p3 = time_p2 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
#[qs_test]
async fn test_filter_resolve_value(server: &QueryServer) {
let time_p1 = duration_from_epoch_now();
let time_p2 = time_p1 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
let time_p3 = time_p2 + Duration::from_secs(CHANGELOG_MAX_AGE * 2);
let server_txn = server.write(time_p1);
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
let mut server_txn = server.write(time_p1).await;
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["object", "person", "account"],
"name": ["testperson1"],
@ -1804,9 +1803,9 @@ mod tests {
"displayname": ["testperson1"]
}
}"#,
);
let e2: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
);
let e2: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(
r#"{
"attrs": {
"class": ["object", "person"],
"name": ["testperson2"],
@ -1815,152 +1814,147 @@ mod tests {
"displayname": ["testperson2"]
}
}"#,
);
);
// We need to add these and then push through the state machine.
let e_ts = entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("person")),
("name", Value::new_iname("testperson3")),
(
"uuid",
Value::new_uuids("9557f49c-97a5-4277-a9a5-097d17eb8317").expect("uuid")
),
("description", Value::new_utf8s("testperson3")),
("displayname", Value::new_utf8s("testperson3"))
);
// We need to add these and then push through the state machine.
let e_ts = entry_init!(
("class", Value::new_class("object")),
("class", Value::new_class("person")),
("name", Value::new_iname("testperson3")),
(
"uuid",
Value::new_uuids("9557f49c-97a5-4277-a9a5-097d17eb8317").expect("uuid")
),
("description", Value::new_utf8s("testperson3")),
("displayname", Value::new_utf8s("testperson3"))
);
let ce = CreateEvent::new_internal(vec![e1, e2, e_ts]);
let cr = server_txn.create(&ce);
assert!(cr.is_ok());
let ce = CreateEvent::new_internal(vec![e1, e2, e_ts]);
let cr = server_txn.create(&ce);
assert!(cr.is_ok());
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testperson3")
)])))
};
assert!(server_txn.delete(&de_sin).is_ok());
let de_sin = unsafe {
DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
"name",
PartialValue::new_iname("testperson3")
)])))
};
assert!(server_txn.delete(&de_sin).is_ok());
// Commit
assert!(server_txn.commit().is_ok());
// Commit
assert!(server_txn.commit().is_ok());
// Now, establish enough time for the recycled items to be purged.
let server_txn = server.write(time_p2);
assert!(server_txn.purge_recycled().is_ok());
assert!(server_txn.commit().is_ok());
// Now, establish enough time for the recycled items to be purged.
let server_txn = server.write(time_p2).await;
assert!(server_txn.purge_recycled().is_ok());
assert!(server_txn.commit().is_ok());
let server_txn = server.write(time_p3);
assert!(server_txn.purge_tombstones().is_ok());
let server_txn = server.write(time_p3).await;
assert!(server_txn.purge_tombstones().is_ok());
// ===== ✅ now ready to test!
// ===== ✅ now ready to test!
// Resolving most times should yield expected results
let t1 = vs_utf8!["teststring".to_string()] as _;
let r1 = server_txn.resolve_valueset(&t1);
assert!(r1 == Ok(vec!["teststring".to_string()]));
// Resolving most times should yield expected results
let t1 = vs_utf8!["teststring".to_string()] as _;
let r1 = server_txn.resolve_valueset(&t1);
assert!(r1 == Ok(vec!["teststring".to_string()]));
// Resolve UUID with matching spn
let t_uuid =
vs_refer![Uuid::parse_str("cc8e95b4-c24f-4d68-ba54-8bed76f63930").unwrap()] as _;
let r_uuid = server_txn.resolve_valueset(&t_uuid);
debug!("{:?}", r_uuid);
assert!(r_uuid == Ok(vec!["testperson1@example.com".to_string()]));
// Resolve UUID with matching spn
let t_uuid =
vs_refer![Uuid::parse_str("cc8e95b4-c24f-4d68-ba54-8bed76f63930").unwrap()] as _;
let r_uuid = server_txn.resolve_valueset(&t_uuid);
debug!("{:?}", r_uuid);
assert!(r_uuid == Ok(vec!["testperson1@example.com".to_string()]));
// Resolve UUID with matching name
let t_uuid =
vs_refer![Uuid::parse_str("a67c0c71-0b35-4218-a6b0-22d23d131d27").unwrap()] as _;
let r_uuid = server_txn.resolve_valueset(&t_uuid);
debug!("{:?}", r_uuid);
assert!(r_uuid == Ok(vec!["testperson2".to_string()]));
// Resolve UUID with matching name
let t_uuid =
vs_refer![Uuid::parse_str("a67c0c71-0b35-4218-a6b0-22d23d131d27").unwrap()] as _;
let r_uuid = server_txn.resolve_valueset(&t_uuid);
debug!("{:?}", r_uuid);
assert!(r_uuid == Ok(vec!["testperson2".to_string()]));
// Resolve UUID non-exist
let t_uuid_non =
vs_refer![Uuid::parse_str("b83e98f0-3d2e-41d2-9796-d8d993289c86").unwrap()] as _;
let r_uuid_non = server_txn.resolve_valueset(&t_uuid_non);
debug!("{:?}", r_uuid_non);
assert!(r_uuid_non == Ok(vec!["b83e98f0-3d2e-41d2-9796-d8d993289c86".to_string()]));
// Resolve UUID non-exist
let t_uuid_non =
vs_refer![Uuid::parse_str("b83e98f0-3d2e-41d2-9796-d8d993289c86").unwrap()] as _;
let r_uuid_non = server_txn.resolve_valueset(&t_uuid_non);
debug!("{:?}", r_uuid_non);
assert!(r_uuid_non == Ok(vec!["b83e98f0-3d2e-41d2-9796-d8d993289c86".to_string()]));
// Resolve UUID to tombstone/recycled (same an non-exst)
let t_uuid_ts =
vs_refer![Uuid::parse_str("9557f49c-97a5-4277-a9a5-097d17eb8317").unwrap()] as _;
let r_uuid_ts = server_txn.resolve_valueset(&t_uuid_ts);
debug!("{:?}", r_uuid_ts);
assert!(r_uuid_ts == Ok(vec!["9557f49c-97a5-4277-a9a5-097d17eb8317".to_string()]));
})
// Resolve UUID to tombstone/recycled (same an non-exst)
let t_uuid_ts =
vs_refer![Uuid::parse_str("9557f49c-97a5-4277-a9a5-097d17eb8317").unwrap()] as _;
let r_uuid_ts = server_txn.resolve_valueset(&t_uuid_ts);
debug!("{:?}", r_uuid_ts);
assert!(r_uuid_ts == Ok(vec!["9557f49c-97a5-4277-a9a5-097d17eb8317".to_string()]));
}
#[test]
fn test_filter_depth_limits() {
run_test!(|server: &QueryServer| {
let r_txn = server.read();
#[qs_test]
async fn test_filter_depth_limits(server: &QueryServer) {
let r_txn = server.read().await;
let mut inv_proto = ProtoFilter::Pres("class".to_string());
for _i in 0..(FILTER_DEPTH_MAX + 1) {
inv_proto = ProtoFilter::And(vec![inv_proto]);
}
let mut inv_proto = ProtoFilter::Pres("class".to_string());
for _i in 0..(FILTER_DEPTH_MAX + 1) {
inv_proto = ProtoFilter::And(vec![inv_proto]);
}
let mut inv_ldap = LdapFilter::Present("class".to_string());
for _i in 0..(FILTER_DEPTH_MAX + 1) {
inv_ldap = LdapFilter::And(vec![inv_ldap]);
}
let mut inv_ldap = LdapFilter::Present("class".to_string());
for _i in 0..(FILTER_DEPTH_MAX + 1) {
inv_ldap = LdapFilter::And(vec![inv_ldap]);
}
let ev = Identity::from_internal();
let ev = Identity::from_internal();
// Test proto + read
let res = Filter::from_ro(&ev, &inv_proto, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// Test proto + read
let res = Filter::from_ro(&ev, &inv_proto, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// ldap
let res = Filter::from_ldap_ro(&ev, &inv_ldap, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// ldap
let res = Filter::from_ldap_ro(&ev, &inv_ldap, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// Can only have one db conn at a time.
std::mem::drop(r_txn);
// Can only have one db conn at a time.
std::mem::drop(r_txn);
// proto + write
let wr_txn = server.write(duration_from_epoch_now());
let res = Filter::from_rw(&ev, &inv_proto, &wr_txn);
assert!(res == Err(OperationError::ResourceLimit));
})
// proto + write
let wr_txn = server.write(duration_from_epoch_now()).await;
let res = Filter::from_rw(&ev, &inv_proto, &wr_txn);
assert!(res == Err(OperationError::ResourceLimit));
}
#[test]
fn test_filter_max_element_limits() {
run_test!(|server: &QueryServer| {
const LIMIT: usize = 4;
let r_txn = server.read();
#[qs_test]
async fn test_filter_max_element_limits(server: &QueryServer) {
const LIMIT: usize = 4;
let r_txn = server.read().await;
let inv_proto = ProtoFilter::And(
(0..(LIMIT * 2))
.map(|_| ProtoFilter::Pres("class".to_string()))
.collect(),
);
let inv_proto = ProtoFilter::And(
(0..(LIMIT * 2))
.map(|_| ProtoFilter::Pres("class".to_string()))
.collect(),
);
let inv_ldap = LdapFilter::And(
(0..(LIMIT * 2))
.map(|_| LdapFilter::Present("class".to_string()))
.collect(),
);
let inv_ldap = LdapFilter::And(
(0..(LIMIT * 2))
.map(|_| LdapFilter::Present("class".to_string()))
.collect(),
);
let mut ev = Identity::from_internal();
ev.limits.filter_max_elements = LIMIT;
let mut ev = Identity::from_internal();
ev.limits.filter_max_elements = LIMIT;
// Test proto + read
let res = Filter::from_ro(&ev, &inv_proto, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// Test proto + read
let res = Filter::from_ro(&ev, &inv_proto, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// ldap
let res = Filter::from_ldap_ro(&ev, &inv_ldap, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// ldap
let res = Filter::from_ldap_ro(&ev, &inv_ldap, &r_txn);
assert!(res == Err(OperationError::ResourceLimit));
// Can only have one db conn at a time.
std::mem::drop(r_txn);
// Can only have one db conn at a time.
std::mem::drop(r_txn);
// proto + write
let wr_txn = server.write(duration_from_epoch_now());
let res = Filter::from_rw(&ev, &inv_proto, &wr_txn);
assert!(res == Err(OperationError::ResourceLimit));
})
// proto + write
let wr_txn = server.write(duration_from_epoch_now()).await;
let res = Filter::from_rw(&ev, &inv_proto, &wr_txn);
assert!(res == Err(OperationError::ResourceLimit));
}
}

View file

@ -502,7 +502,7 @@ impl DestroySessionTokenEvent {
impl<'a> IdmServerProxyWriteTransaction<'a> {
pub fn account_destroy_session_token(
&self,
&mut self,
dte: &DestroySessionTokenEvent,
) -> Result<(), OperationError> {
// Delete the attribute with uuid.
@ -534,7 +534,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
}
pub fn service_account_into_person(
&self,
&mut self,
ident: &Identity,
target_uuid: Uuid,
) -> Result<(), OperationError> {

View file

@ -1500,7 +1500,7 @@ mod tests {
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed| {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let testaccount_uuid = Uuid::new_v4();
@ -1607,7 +1607,7 @@ mod tests {
idms: &IdmServer,
ct: Duration,
) -> (CredentialUpdateSessionToken, CredentialUpdateSessionStatus) {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let e2 = entry_init!(
("class", Value::new_class("object")),
@ -1642,7 +1642,7 @@ mod tests {
idms: &IdmServer,
ct: Duration,
) -> (CredentialUpdateSessionToken, CredentialUpdateSessionStatus) {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let testperson = idms_prox_write
.qs_write
@ -1660,7 +1660,7 @@ mod tests {
}
fn commit_session(idms: &IdmServer, ct: Duration, cust: CredentialUpdateSessionToken) {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
idms_prox_write
.commit_credential_update(&cust, ct)

View file

@ -1416,6 +1416,8 @@ mod tests {
use crate::idm::server::{IdmServer, IdmServerTransaction};
use crate::prelude::*;
use async_std::task;
const TEST_CURRENT_TIME: u64 = 6000;
const UAT_EXPIRE: u64 = 5;
const TOKEN_EXPIRE: u64 = 900;
@ -1466,7 +1468,7 @@ mod tests {
enable_pkce: bool,
enable_legacy_crypto: bool,
) -> (String, UserAuthToken, Identity, Uuid) {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let uuid = Uuid::new_v4();
@ -1543,7 +1545,7 @@ mod tests {
ct: Duration,
authtype: AuthType,
) -> (UserAuthToken, Identity) {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let account = idms_prox_write
.target_to_account(&UUID_IDM_ADMIN)
.expect("account must exist");
@ -1567,7 +1569,7 @@ mod tests {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// Get an ident/uat for now.
@ -1636,7 +1638,7 @@ mod tests {
let (idm_admin_uat, idm_admin_ident) = setup_idm_admin(idms, ct, AuthType::PasswordMfa);
// Need a uat from a user not in the group. Probs anonymous.
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -1797,7 +1799,7 @@ mod tests {
let (_secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let (uat2, ident2) = {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let account = idms_prox_write
.target_to_account(&UUID_IDM_ADMIN)
.expect("account must exist");
@ -1811,7 +1813,7 @@ mod tests {
(uat2, ident2)
};
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -1884,7 +1886,7 @@ mod tests {
+ Duration::from_secs(TEST_CURRENT_TIME + UAT_EXPIRE - 1),
);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// == Setup the authorisation request
let (code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -2045,7 +2047,7 @@ mod tests {
let (secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let client_authz = Some(base64::encode(format!("test_resource_server:{}", secret)));
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// == Setup the authorisation request
let (code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -2109,7 +2111,7 @@ mod tests {
drop(idms_prox_read);
// start a write,
let idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
// Expire the account, should cause introspect to return inactive.
let v_expire =
Value::new_datetime_epoch(Duration::from_secs(TEST_CURRENT_TIME - 1));
@ -2128,7 +2130,7 @@ mod tests {
// start a new read
// check again.
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let intr_response = idms_prox_read
.check_oauth2_token_introspect(&client_authz.unwrap(), &intr_request, ct)
.expect("Failed to inspect token");
@ -2147,7 +2149,7 @@ mod tests {
let (_secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let (uat2, ident2) = {
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let account = idms_prox_write
.target_to_account(&UUID_IDM_ADMIN)
.expect("account must exist");
@ -2161,7 +2163,7 @@ mod tests {
(uat2, ident2)
};
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let redirect_uri = Url::parse("https://demo.example.com/oauth2/result").unwrap();
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -2226,7 +2228,7 @@ mod tests {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (_secret, _uat, _ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// check the discovery end point works as we expect
assert!(
@ -2367,7 +2369,7 @@ mod tests {
let (secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let client_authz = Some(base64::encode(format!("test_resource_server:{}", secret)));
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let (code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -2491,7 +2493,7 @@ mod tests {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (_secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, false, false);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// == Setup the authorisation request
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
@ -2525,7 +2527,7 @@ mod tests {
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, false, true);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// The public key url should offer an rs key
// discovery should offer RS256
let discovery = idms_prox_read
@ -2623,7 +2625,7 @@ mod tests {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let (_secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, true, false);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
let consent_request =
@ -2653,12 +2655,12 @@ mod tests {
};
// Manually submit the consent.
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
assert!(idms_prox_write.process_oauth2consentgrant(&o2cg).is_ok());
assert!(idms_prox_write.commit().is_ok());
// == Now try the authorise again, should be in the permitted state.
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// We need to reload our identity
let ident = idms_prox_read
@ -2680,7 +2682,7 @@ mod tests {
drop(idms_prox_read);
// Great! Now change the scopes on the oauth2 instance, this revokes the permit.
let idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let me_extend_scopes = unsafe {
ModifyEvent::new_internal_invalid(
@ -2704,7 +2706,7 @@ mod tests {
// And do the workflow once more to see if we need to consent again.
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// We need to reload our identity
let ident = idms_prox_read
@ -2747,7 +2749,7 @@ mod tests {
// Success! We had to consent again due to the change :)
// Now change the supplemental scopes on the oauth2 instance, this revokes the permit.
let idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let me_extend_scopes = unsafe {
ModifyEvent::new_internal_invalid(
@ -2771,7 +2773,7 @@ mod tests {
// And do the workflow once more to see if we need to consent again.
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// We need to reload our identity
let ident = idms_prox_read
@ -2827,7 +2829,7 @@ mod tests {
// Assert there are no consent maps yet.
assert!(ident.get_oauth2_consent_scopes(o2rs_uuid).is_none());
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
let (_code_verifier, code_challenge) = create_code_verifier!("Whar Garble");
let consent_request =
@ -2857,7 +2859,7 @@ mod tests {
};
// Manually submit the consent.
let mut idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
assert!(idms_prox_write.process_oauth2consentgrant(&o2cg).is_ok());
let ident = idms_prox_write
@ -2917,7 +2919,7 @@ mod tests {
// Enable pkce is set to FALSE
let (secret, uat, ident, _) = setup_oauth2_resource_server(idms, ct, false, false);
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// Get an ident/uat for now.

View file

@ -162,7 +162,7 @@ impl IdmServer {
// Get the domain name, as the relying party id.
let (rp_id, rp_name, fernet_private_key, es256_private_key, pw_badlist_set, oauth2rs_set) = {
let qs_read = task::block_on(qs.read_async());
let qs_read = task::block_on(qs.read());
(
qs_read.get_domain_name().to_string(),
qs_read.get_domain_display_name().to_string(),
@ -257,12 +257,12 @@ impl IdmServer {
}
pub async fn auth_async(&self) -> IdmServerAuthTransaction<'_> {
let qs_read = self.qs.read().await;
let mut sid = [0; 4];
let mut rng = StdRng::from_entropy();
rng.fill(&mut sid);
let qs_read = self.qs.read_async().await;
IdmServerAuthTransaction {
session_ticket: &self.session_ticket,
sessions: &self.sessions,
@ -277,34 +277,24 @@ impl IdmServer {
}
}
/// Perform a blocking read transaction on the database.
#[cfg(test)]
pub fn proxy_read<'a>(&'a self) -> IdmServerProxyReadTransaction<'a> {
task::block_on(self.proxy_read_async())
}
/// Read from the database, in a transaction.
#[instrument(level = "debug", skip_all)]
pub async fn proxy_read_async(&self) -> IdmServerProxyReadTransaction<'_> {
pub async fn proxy_read(&self) -> IdmServerProxyReadTransaction<'_> {
IdmServerProxyReadTransaction {
qs_read: self.qs.read_async().await,
qs_read: self.qs.read().await,
uat_jwt_validator: self.uat_jwt_validator.read(),
oauth2rs: self.oauth2rs.read(),
async_tx: self.async_tx.clone(),
}
}
#[cfg(test)]
pub fn proxy_write(&self, ts: Duration) -> IdmServerProxyWriteTransaction {
task::block_on(self.proxy_write_async(ts))
}
#[instrument(level = "debug", skip_all)]
pub async fn proxy_write_async(&self, ts: Duration) -> IdmServerProxyWriteTransaction<'_> {
pub async fn proxy_write(&self, ts: Duration) -> IdmServerProxyWriteTransaction<'_> {
let qs_write = self.qs.write(ts).await;
let mut sid = [0; 4];
let mut rng = StdRng::from_entropy();
rng.fill(&mut sid);
let qs_write = self.qs.write_async(ts).await;
IdmServerProxyWriteTransaction {
cred_update_sessions: self.cred_update_sessions.write(),
@ -327,7 +317,7 @@ impl IdmServer {
pub async fn cred_update_transaction_async(&self) -> IdmServerCredUpdateTransaction<'_> {
IdmServerCredUpdateTransaction {
_qs_read: self.qs.read_async().await,
_qs_read: self.qs.read().await,
// sid: Sid,
webauthn: &self.webauthn,
pw_badlist_cache: self.pw_badlist_cache.read(),
@ -343,7 +333,7 @@ impl IdmServer {
ts: Duration,
da: DelayedAction,
) -> Result<bool, OperationError> {
let mut pw = self.proxy_write_async(ts).await;
let mut pw = self.proxy_write(ts).await;
pw.process_delayedaction(da)
.and_then(|_| pw.commit())
.map(|()| true)
@ -2347,11 +2337,11 @@ mod tests {
)
}
fn init_admin_w_password(qs: &QueryServer, pw: &str) -> Result<(), OperationError> {
async fn init_admin_w_password(qs: &QueryServer, pw: &str) -> Result<(), OperationError> {
let p = CryptoPolicy::minimum();
let cred = Credential::new_password_only(&p, pw)?;
let v_cred = Value::new_credential("primary", cred);
let qs_write = qs.write(duration_from_epoch_now());
let mut qs_write = qs.write(duration_from_epoch_now()).await;
// now modify and provide a primary credential.
let me_inv_m = unsafe {
@ -2457,7 +2447,8 @@ mod tests {
fn test_idm_simple_password_auth() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
check_admin_password(idms, TEST_PASSWORD);
// Clear our the session record
@ -2472,7 +2463,8 @@ mod tests {
fn test_idm_simple_password_spn_auth() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
let sid = init_admin_authsession_sid(
idms,
@ -2530,7 +2522,8 @@ mod tests {
fn test_idm_simple_password_invalid() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
let sid = init_admin_authsession_sid(
idms,
Duration::from_secs(TEST_CURRENT_TIME),
@ -2583,7 +2576,8 @@ mod tests {
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let pce = PasswordChangeEvent::new_internal(&UUID_ADMIN, TEST_PASSWORD);
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
assert!(idms_prox_write.set_account_password(&pce).is_ok());
assert!(idms_prox_write.set_account_password(&pce).is_ok());
assert!(idms_prox_write.commit().is_ok());
@ -2597,7 +2591,8 @@ mod tests {
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let pce = PasswordChangeEvent::new_internal(&UUID_ANONYMOUS, TEST_PASSWORD);
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
assert!(idms_prox_write.set_account_password(&pce).is_err());
assert!(idms_prox_write.commit().is_ok());
}
@ -2608,7 +2603,8 @@ mod tests {
fn test_idm_session_expire() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
let sid = init_admin_authsession_sid(
idms,
Duration::from_secs(TEST_CURRENT_TIME),
@ -2637,7 +2633,8 @@ mod tests {
fn test_idm_regenerate_radius_secret() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let rrse = RegenerateRadiusSecretEvent::new_internal(UUID_ADMIN.clone());
// Generates a new credential when none exists
@ -2657,7 +2654,8 @@ mod tests {
fn test_idm_radius_secret_rejected_from_account_credential() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let rrse = RegenerateRadiusSecretEvent::new_internal(UUID_ADMIN.clone());
let r1 = idms_prox_write
@ -2682,14 +2680,15 @@ mod tests {
fn test_idm_radiusauthtoken() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let rrse = RegenerateRadiusSecretEvent::new_internal(UUID_ADMIN.clone());
let r1 = idms_prox_write
.regenerate_radius_secret(&rrse)
.expect("Failed to reset radius credential 1");
idms_prox_write.commit().expect("failed to commit");
let mut idms_prox_read = idms.proxy_read();
let mut idms_prox_read = task::block_on(idms.proxy_read());
let rate = RadiusAuthTokenEvent::new_internal(UUID_ADMIN.clone());
let tok_r = idms_prox_read
.get_radiusauthtoken(&rate, duration_from_epoch_now())
@ -2706,7 +2705,8 @@ mod tests {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
// len check
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let pce = PasswordChangeEvent::new_internal(&UUID_ADMIN, "password");
let e = idms_prox_write.set_account_password(&pce);
@ -2739,7 +2739,8 @@ mod tests {
fn test_idm_simple_password_reject_badlist() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
// Check that the badlist password inserted is rejected.
let pce = PasswordChangeEvent::new_internal(&UUID_ADMIN, "bad@no3IBTyqHu$list");
@ -2755,7 +2756,8 @@ mod tests {
fn test_idm_unixusertoken() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
// Modify admin to have posixaccount
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
@ -2793,7 +2795,7 @@ mod tests {
idms_prox_write.commit().expect("failed to commit");
let mut idms_prox_read = idms.proxy_read();
let mut idms_prox_read = task::block_on(idms.proxy_read());
let ugte = UnixGroupTokenEvent::new_internal(
Uuid::parse_str("01609135-a1c4-43d5-966b-a28227644445")
@ -2837,7 +2839,8 @@ mod tests {
fn test_idm_simple_unix_password_reset() {
run_idm_test!(
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
// make the admin a valid posix account
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
@ -2881,7 +2884,8 @@ mod tests {
assert!(idms_auth.commit().is_ok());
// Check deleting the password
let idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let me_purge_up = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
@ -2911,12 +2915,13 @@ mod tests {
#[test]
fn test_idm_simple_password_upgrade() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
|_qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
// Assert the delayed action queue is empty
idms_delayed.check_is_empty_or_panic();
// Setup the admin w_ an imported password.
{
let qs_write = qs.write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
// now modify and provide a primary credential.
let me_inv_m = unsafe {
ModifyEvent::new_internal_invalid(
@ -2928,8 +2933,8 @@ mod tests {
)
};
// go!
assert!(qs_write.modify(&me_inv_m).is_ok());
qs_write.commit().expect("failed to commit");
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
assert!(idms_prox_write.commit().is_ok());
}
// Still empty
idms_delayed.check_is_empty_or_panic();
@ -2965,7 +2970,8 @@ mod tests {
// Assert the delayed action queue is empty
idms_delayed.check_is_empty_or_panic();
// Setup the admin with an imported unix pw.
let idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let im_pw = "{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM";
let pw = Password::try_from(im_pw).expect("failed to parse");
@ -3027,8 +3033,8 @@ mod tests {
const TEST_EXPIRE_TIME: u64 = TEST_CURRENT_TIME + 120;
const TEST_AFTER_EXPIRY: u64 = TEST_CURRENT_TIME + 240;
fn set_admin_valid_time(qs: &QueryServer) {
let qs_write = qs.write(duration_from_epoch_now());
async fn set_admin_valid_time(qs: &QueryServer) {
let mut qs_write = qs.write(duration_from_epoch_now()).await;
let v_valid_from = Value::new_datetime_epoch(Duration::from_secs(TEST_VALID_FROM_TIME));
let v_expire = Value::new_datetime_epoch(Duration::from_secs(TEST_EXPIRE_TIME));
@ -3055,10 +3061,11 @@ mod tests {
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed| {
// Any account taht is not yet valrid / expired can't auth.
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
// Set the valid bounds high/low
// TEST_VALID_FROM_TIME/TEST_EXPIRE_TIME
set_admin_valid_time(qs);
task::block_on(set_admin_valid_time(qs));
let time_low = Duration::from_secs(TEST_NOT_YET_VALID_TIME);
let time_high = Duration::from_secs(TEST_AFTER_EXPIRY);
@ -3114,14 +3121,16 @@ mod tests {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed| {
// Any account that is expired can't unix auth.
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
set_admin_valid_time(qs);
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
task::block_on(set_admin_valid_time(qs));
let time_low = Duration::from_secs(TEST_NOT_YET_VALID_TIME);
let time_high = Duration::from_secs(TEST_AFTER_EXPIRY);
// make the admin a valid posix account
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
@ -3161,7 +3170,7 @@ mod tests {
idms_auth.commit().expect("Must not fail");
// Also check the generated unix tokens are invalid.
let mut idms_prox_read = idms.proxy_read();
let mut idms_prox_read = task::block_on(idms.proxy_read());
let uute = UnixUserTokenEvent::new_internal(UUID_ADMIN.clone());
let tok_r = idms_prox_read
@ -3187,20 +3196,22 @@ mod tests {
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed| {
// Any account not valid/expiry should not return
// a radius packet.
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
set_admin_valid_time(qs);
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
task::block_on(set_admin_valid_time(qs));
let time_low = Duration::from_secs(TEST_NOT_YET_VALID_TIME);
let time_high = Duration::from_secs(TEST_AFTER_EXPIRY);
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let rrse = RegenerateRadiusSecretEvent::new_internal(UUID_ADMIN.clone());
let _r1 = idms_prox_write
.regenerate_radius_secret(&rrse)
.expect("Failed to reset radius credential 1");
idms_prox_write.commit().expect("failed to commit");
let mut idms_prox_read = idms.proxy_read();
let mut idms_prox_read = task::block_on(idms.proxy_read());
let rate = RadiusAuthTokenEvent::new_internal(UUID_ADMIN.clone());
let tok_r = idms_prox_read.get_radiusauthtoken(&rate, time_low);
@ -3225,7 +3236,8 @@ mod tests {
fn test_idm_account_softlocking() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
// Auth invalid, no softlock present.
let sid = init_admin_authsession_sid(
@ -3378,7 +3390,8 @@ mod tests {
fn test_idm_account_softlocking_interleaved() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
// Start an *early* auth session.
let sid_early = init_admin_authsession_sid(
@ -3472,9 +3485,11 @@ mod tests {
fn test_idm_account_unix_softlocking() {
run_idm_test!(
|qs: &QueryServer, idms: &IdmServer, _idms_delayed: &mut IdmServerDelayed| {
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
// make the admin a valid posix account
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("name", PartialValue::new_iname("admin"))),
@ -3535,7 +3550,8 @@ mod tests {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let expiry = ct + Duration::from_secs(AUTH_SESSION_EXPIRY + 1);
// Do an authenticate
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
let token = check_admin_password(idms, TEST_PASSWORD);
// Clear our the session record
@ -3545,7 +3561,7 @@ mod tests {
assert!(Ok(true) == r);
idms_delayed.check_is_empty_or_panic();
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// Check it's valid.
idms_prox_read
@ -3580,7 +3596,8 @@ mod tests {
assert!(post_grace < expiry);
// Do an authenticate
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
let token = check_admin_password(idms, TEST_PASSWORD);
// Process the session info.
@ -3596,7 +3613,7 @@ mod tests {
.expect("Embedded jwk not found");
let uat_inner = uat_inner.into_inner();
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// Check it's valid.
idms_prox_read
@ -3611,14 +3628,14 @@ mod tests {
drop(idms_prox_read);
// Mark the session as invalid now.
let idms_prox_write = idms.proxy_write(ct.clone());
let mut idms_prox_write = task::block_on(idms.proxy_write(ct.clone()));
let dte =
DestroySessionTokenEvent::new_internal(uat_inner.uuid, uat_inner.session_id);
assert!(idms_prox_write.account_destroy_session_token(&dte).is_ok());
assert!(idms_prox_write.commit().is_ok());
// Now check again with the session destroyed.
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// Now, within gracewindow, it's still valid.
idms_prox_read
@ -3642,7 +3659,7 @@ mod tests {
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed| {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let mut idms_prox_write = idms.proxy_write(ct.clone());
let mut idms_prox_write = task::block_on(idms.proxy_write(ct.clone()));
// get an account.
let account = idms_prox_write
@ -3746,7 +3763,8 @@ mod tests {
|qs: &QueryServer, idms: &IdmServer, idms_delayed: &mut IdmServerDelayed| {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
init_admin_w_password(qs, TEST_PASSWORD).expect("Failed to setup admin account");
task::block_on(init_admin_w_password(qs, TEST_PASSWORD))
.expect("Failed to setup admin account");
let token = check_admin_password(idms, TEST_PASSWORD);
// Clear the session record
@ -3754,7 +3772,7 @@ mod tests {
assert!(matches!(da, DelayedAction::AuthSessionRecord(_)));
idms_delayed.check_is_empty_or_panic();
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
// Check it's valid.
idms_prox_read
@ -3768,7 +3786,7 @@ mod tests {
//
// fernet_private_key_str
// es256_private_key_der
let idms_prox_write = idms.proxy_write(ct.clone());
let mut idms_prox_write = task::block_on(idms.proxy_write(ct.clone()));
let me_reset_tokens = unsafe {
ModifyEvent::new_internal_invalid(
filter!(f_eq("uuid", PartialValue::new_uuid(UUID_DOMAIN_INFO))),
@ -3789,7 +3807,7 @@ mod tests {
assert!(matches!(da, DelayedAction::AuthSessionRecord(_)));
idms_delayed.check_is_empty_or_panic();
let idms_prox_read = idms.proxy_read();
let idms_prox_read = task::block_on(idms.proxy_read());
assert!(idms_prox_read
.validate_and_parse_token_to_ident(Some(token.as_str()), ct)
.is_err());
@ -3807,7 +3825,7 @@ mod tests {
idms: &IdmServer,
_idms_delayed: &mut IdmServerDelayed| {
let ct = Duration::from_secs(TEST_CURRENT_TIME);
let idms_prox_write = idms.proxy_write(ct.clone());
let mut idms_prox_write = task::block_on(idms.proxy_write(ct.clone()));
let ident = Identity::from_internal();
let target_uuid = Uuid::new_v4();

View file

@ -188,7 +188,7 @@ impl DestroyApiTokenEvent {
impl<'a> IdmServerProxyWriteTransaction<'a> {
pub fn service_account_generate_api_token(
&self,
&mut self,
gte: &GenerateApiTokenEvent,
ct: Duration,
) -> Result<String, OperationError> {
@ -277,7 +277,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
}
pub fn service_account_destroy_api_token(
&self,
&mut self,
dte: &DestroyApiTokenEvent,
) -> Result<(), OperationError> {
// Delete the attribute with uuid.
@ -379,6 +379,8 @@ mod tests {
use crate::event::CreateEvent;
use crate::idm::server::IdmServerTransaction;
use async_std::task;
const TEST_CURRENT_TIME: u64 = 6000;
#[test]
@ -390,7 +392,7 @@ mod tests {
let past_grc = Duration::from_secs(TEST_CURRENT_TIME + 1) + GRACE_WINDOW;
let exp = Duration::from_secs(TEST_CURRENT_TIME + 6000);
let post_exp = Duration::from_secs(TEST_CURRENT_TIME + 6010);
let idms_prox_write = idms.proxy_write(ct);
let mut idms_prox_write = task::block_on(idms.proxy_write(ct));
let testaccount_uuid = Uuid::new_v4();

View file

@ -61,7 +61,7 @@ pub struct LdapServer {
impl LdapServer {
pub fn new(idms: &IdmServer) -> Result<Self, OperationError> {
// let ct = duration_from_epoch_now();
let idms_prox_read = task::block_on(idms.proxy_read_async());
let idms_prox_read = task::block_on(idms.proxy_read());
// This is the rootdse path.
// get the domain_info item
let domain_entry = idms_prox_read
@ -254,7 +254,7 @@ impl LdapServer {
admin_info!(attr = ?k_attrs, "LDAP Search Request Mapped Attrs");
let ct = duration_from_epoch_now();
let idm_read = idms.proxy_read_async().await;
let idm_read = idms.proxy_read().await;
// Now start the txn - we need it for resolving filter components.
// join the filter, with ext_filter
@ -564,7 +564,8 @@ mod tests {
|_qs: &QueryServer, idms: &IdmServer, _idms_delayed: &IdmServerDelayed| {
let ldaps = LdapServer::new(idms).expect("failed to start ldap");
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now());
let mut idms_prox_write =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
// make the admin a valid posix account
let me_posix = unsafe {
ModifyEvent::new_internal_invalid(
@ -755,7 +756,8 @@ mod tests {
("ssh_publickey", Value::new_sshkey_str("test", ssh_ed25519))
);
let server_txn = idms.proxy_write(duration_from_epoch_now());
let mut server_txn =
task::block_on(idms.proxy_write(duration_from_epoch_now()));
let ce = CreateEvent::new_internal(vec![e1]);
assert!(server_txn
.qs_write
@ -925,7 +927,7 @@ mod tests {
let ct = duration_from_epoch_now();
let server_txn = idms.proxy_write(ct);
let mut server_txn = task::block_on(idms.proxy_write(ct));
let ce = CreateEvent::new_internal(vec![e1, e2]);
assert!(server_txn.qs_write.create(&ce).is_ok());

View file

@ -52,6 +52,8 @@ mod repl;
pub mod schema;
pub mod server;
pub mod status;
#[cfg(test)]
mod testkit;
/// A prelude of imports that should be imported by all other Kanidm modules to
/// help make imports cleaner.
@ -89,4 +91,7 @@ pub mod prelude {
ValueSetSecret, ValueSetSpn, ValueSetSyntax, ValueSetT, ValueSetUint32, ValueSetUtf8,
ValueSetUuid,
};
#[cfg(test)]
pub use kanidmd_lib_macros::*;
}

View file

@ -12,15 +12,13 @@ macro_rules! setup_test {
Backend::new(BackendConfig::new_test(), idxmeta, false).expect("Failed to init BE");
let qs = QueryServer::new(be, schema_outer, "example.com".to_string());
qs.initialise_helper(duration_from_epoch_now())
async_std::task::block_on(qs.initialise_helper(duration_from_epoch_now()))
.expect("init failed!");
qs
}};
(
$preload_entries:expr
) => {{
use async_std::task;
use crate::utils::duration_from_epoch_now;
let _ = sketching::test_init();
@ -28,18 +26,18 @@ macro_rules! setup_test {
// Create an in memory BE
let schema_outer = Schema::new().expect("Failed to init schema");
let idxmeta = {
let schema_txn = schema_outer.write_blocking();
let schema_txn = schema_outer.write();
schema_txn.reload_idxmeta()
};
let be =
Backend::new(BackendConfig::new_test(), idxmeta, false).expect("Failed to init BE");
let qs = QueryServer::new(be, schema_outer, "example.com".to_string());
qs.initialise_helper(duration_from_epoch_now())
async_std::task::block_on(qs.initialise_helper(duration_from_epoch_now()))
.expect("init failed!");
if !$preload_entries.is_empty() {
let qs_write = task::block_on(qs.write_async(duration_from_epoch_now()));
let mut qs_write = async_std::task::block_on(qs.write(duration_from_epoch_now()));
qs_write
.internal_create($preload_entries)
.expect("Failed to preload entries");
@ -49,60 +47,6 @@ macro_rules! setup_test {
}};
}
#[cfg(test)]
macro_rules! run_test_no_init {
($test_fn:expr) => {{
use crate::be::{Backend, BackendConfig};
use crate::prelude::*;
use crate::schema::Schema;
use crate::utils::duration_from_epoch_now;
let _ = sketching::test_init();
let schema_outer = Schema::new().expect("Failed to init schema");
let idxmeta = {
let schema_txn = schema_outer.write_blocking();
schema_txn.reload_idxmeta()
};
let be = match Backend::new(BackendConfig::new_test(), idxmeta, false) {
Ok(be) => be,
Err(e) => {
error!("{:?}", e);
panic!()
}
};
let test_server = QueryServer::new(be, schema_outer, "example.com".to_string());
$test_fn(&test_server);
// Any needed teardown?
// Make sure there are no errors.
// let verifications = test_server.verify();
// assert!(verifications.len() == 0);
}};
}
#[cfg(test)]
macro_rules! run_test {
($test_fn:expr) => {{
use crate::be::{Backend, BackendConfig};
use crate::prelude::*;
use crate::schema::Schema;
#[allow(unused_imports)]
use crate::utils::duration_from_epoch_now;
let _ = sketching::test_init();
let test_server = setup_test!();
$test_fn(&test_server);
// Any needed teardown?
// Make sure there are no errors.
let verifications = test_server.verify();
trace!("Verification result: {:?}", verifications);
assert!(verifications.len() == 0);
}};
}
#[cfg(test)]
macro_rules! entry_str_to_account {
($entry_str:expr) => {{
@ -155,7 +99,7 @@ macro_rules! run_idm_test_inner {
$test_fn(&test_server, &test_idm_server, &mut idms_delayed);
// Any needed teardown?
// Make sure there are no errors.
assert!(test_server.verify().len() == 0);
assert!(async_std::task::block_on(test_server.verify()).len() == 0);
idms_delayed.check_is_empty_or_panic();
}};
}
@ -207,7 +151,7 @@ macro_rules! run_create_test {
};
{
let qs_write = qs.write(duration_from_epoch_now());
let mut qs_write = async_std::task::block_on(qs.write(duration_from_epoch_now()));
let r = qs_write.create(&ce);
trace!("test result: {:?}", r);
assert!(r == $expect);
@ -223,7 +167,7 @@ macro_rules! run_create_test {
}
// Make sure there are no errors.
trace!("starting verification");
let ver = qs.verify();
let ver = async_std::task::block_on(qs.verify());
trace!("verification -> {:?}", ver);
assert!(ver.len() == 0);
}};
@ -249,8 +193,8 @@ macro_rules! run_modify_test {
let qs = setup_test!($preload_entries);
{
let qs_write = qs.write(duration_from_epoch_now());
$pre_hook(&qs_write);
let mut qs_write = async_std::task::block_on(qs.write(duration_from_epoch_now()));
$pre_hook(&mut qs_write);
qs_write.commit().expect("commit failure!");
}
@ -262,7 +206,7 @@ macro_rules! run_modify_test {
};
{
let qs_write = qs.write(duration_from_epoch_now());
let mut qs_write = async_std::task::block_on(qs.write(duration_from_epoch_now()));
let r = qs_write.modify(&me);
$check(&qs_write);
trace!("test result: {:?}", r);
@ -278,7 +222,7 @@ macro_rules! run_modify_test {
}
// Make sure there are no errors.
trace!("starting verification");
let ver = qs.verify();
let ver = async_std::task::block_on(qs.verify());
trace!("verification -> {:?}", ver);
assert!(ver.len() == 0);
}};
@ -310,10 +254,10 @@ macro_rules! run_delete_test {
};
{
let qs_write = qs.write(duration_from_epoch_now());
let mut qs_write = async_std::task::block_on(qs.write(duration_from_epoch_now()));
let r = qs_write.delete(&de);
trace!("test result: {:?}", r);
$check(&qs_write);
$check(&mut qs_write);
assert!(r == $expect);
match r {
Ok(_) => {
@ -326,7 +270,7 @@ macro_rules! run_delete_test {
}
// Make sure there are no errors.
trace!("starting verification");
let ver = qs.verify();
let ver = async_std::task::block_on(qs.verify());
trace!("verification -> {:?}", ver);
assert!(ver.len() == 0);
}};

View file

@ -120,7 +120,7 @@ impl Plugin for AttrUnique {
skip(qs, cand, _ce)
)]
fn pre_create_transform(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -138,7 +138,7 @@ impl Plugin for AttrUnique {
#[instrument(level = "debug", name = "attrunique_pre_modify", skip(qs, cand, _me))]
fn pre_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {
@ -155,7 +155,7 @@ impl Plugin for AttrUnique {
}
#[instrument(level = "debug", name = "attrunique_verify", skip(qs))]
fn verify(qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
// Only check live entries, not recycled.
let filt_in = filter!(f_pres("class"));

View file

@ -33,7 +33,7 @@ impl Plugin for Base {
)]
#[allow(clippy::cognitive_complexity)]
fn pre_create_transform(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -153,7 +153,7 @@ impl Plugin for Base {
#[instrument(level = "debug", name = "base_pre_modify", skip(_qs, _cand, me))]
fn pre_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
_cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
me: &ModifyEvent,
) -> Result<(), OperationError> {
@ -172,7 +172,7 @@ impl Plugin for Base {
}
#[instrument(level = "debug", name = "base_verify", skip(qs))]
fn verify(qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
// Search for class = *
let entries = match qs.internal_search(filter!(f_pres("class"))) {
Ok(v) => v,

View file

@ -27,7 +27,7 @@ impl Plugin for Domain {
skip(qs, cand, _ce)
)]
fn pre_create_transform(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -79,7 +79,7 @@ impl Plugin for Domain {
#[instrument(level = "debug", name = "domain_pre_modify", skip(qs, cand, _me))]
fn pre_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {
@ -129,20 +129,18 @@ impl Plugin for Domain {
#[cfg(test)]
mod tests {
// use crate::prelude::*;
use crate::prelude::*;
// test we can create and generate the id
#[test]
fn test_domain_generate_uuid() {
run_test!(|server: &QueryServer| {
let server_txn = server.write(duration_from_epoch_now());
let e_dom = server_txn
.internal_search_uuid(&UUID_DOMAIN_INFO)
.expect("must not fail");
#[qs_test]
async fn test_domain_generate_uuid(server: &QueryServer) {
let server_txn = server.write(duration_from_epoch_now()).await;
let e_dom = server_txn
.internal_search_uuid(&UUID_DOMAIN_INFO)
.expect("must not fail");
let u_dom = server_txn.get_domain_uuid();
let u_dom = server_txn.get_domain_uuid();
assert!(e_dom.attribute_equality("domain_uuid", &PartialValue::new_uuid(u_dom)));
})
assert!(e_dom.attribute_equality("domain_uuid", &PartialValue::new_uuid(u_dom)));
}
}

View file

@ -141,7 +141,7 @@ impl DynGroup {
#[instrument(level = "debug", name = "dyngroup_post_create", skip(qs, cand, ce))]
pub fn post_create(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
ce: &CreateEvent,
) -> Result<Vec<Uuid>, OperationError> {
@ -242,7 +242,7 @@ impl DynGroup {
skip(qs, pre_cand, cand, me)
)]
pub fn post_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
cand: &[Entry<EntrySealed, EntryCommitted>],
me: &ModifyEvent,
@ -352,7 +352,7 @@ impl DynGroup {
// No post_delete handler is needed as refint takes care of this for us.
pub fn verify(_qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
pub fn verify(_qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
vec![]
}
}

View file

@ -1,6 +0,0 @@
// Failure inducing plugin
//
// Designed for complex server tests, this plugin is able to look at Event
// metadata and induce failures in various stages of query server operation
// execution. The idea is that we should be able to test and assert that
// rollback events do not have negative effects on various server elements.

View file

@ -70,7 +70,7 @@ impl Plugin for GidNumber {
skip(_qs, cand, _ce)
)]
fn pre_create_transform(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -83,7 +83,7 @@ impl Plugin for GidNumber {
#[instrument(level = "debug", name = "gidnumber_pre_modify", skip(_qs, cand, _me))]
fn pre_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {

View file

@ -77,7 +77,7 @@ impl Plugin for JwsKeygen {
skip(_qs, cand, _ce)
)]
fn pre_create_transform(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -86,7 +86,7 @@ impl Plugin for JwsKeygen {
#[instrument(level = "debug", name = "jwskeygen_pre_modify", skip(_qs, cand, _me))]
fn pre_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {

View file

@ -96,7 +96,7 @@ fn do_memberof(
#[allow(clippy::cognitive_complexity)]
fn apply_memberof(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
// TODO: Experiment with HashSet/BTreeSet here instead of vec.
// May require https://github.com/rust-lang/rust/issues/62924 to allow poping
mut group_affect: Vec<Uuid>,
@ -212,7 +212,7 @@ impl Plugin for MemberOf {
#[instrument(level = "debug", name = "memberof_post_create", skip(qs, cand, ce))]
fn post_create(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -245,7 +245,7 @@ impl Plugin for MemberOf {
skip(qs, pre_cand, cand, me)
)]
fn post_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
cand: &[Entry<EntrySealed, EntryCommitted>],
me: &ModifyEvent,
@ -310,7 +310,7 @@ impl Plugin for MemberOf {
#[instrument(level = "debug", name = "memberof_post_delete", skip(qs, cand, _de))]
fn post_delete(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
_de: &DeleteEvent,
) -> Result<(), OperationError> {
@ -333,7 +333,7 @@ impl Plugin for MemberOf {
}
#[instrument(level = "debug", name = "memberof_verify", skip(qs))]
fn verify(qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
let mut r = Vec::new();
let filt_in = filter!(f_pres("class"));

View file

@ -15,13 +15,11 @@ mod attrunique;
mod base;
mod domain;
pub(crate) mod dyngroup;
mod failure;
mod gidnumber;
mod jwskeygen;
mod memberof;
mod password_import;
mod protected;
mod recycle;
mod refint;
mod spn;
@ -29,7 +27,7 @@ trait Plugin {
fn id() -> &'static str;
fn pre_create_transform(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
_cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -41,7 +39,7 @@ trait Plugin {
}
fn pre_create(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// List of what we will commit that is valid?
_cand: &[Entry<EntrySealed, EntryNew>],
_ce: &CreateEvent,
@ -51,7 +49,7 @@ trait Plugin {
}
fn post_create(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// List of what we commited that was valid?
_cand: &[Entry<EntrySealed, EntryCommitted>],
_ce: &CreateEvent,
@ -61,7 +59,7 @@ trait Plugin {
}
fn pre_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
_cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {
@ -70,7 +68,7 @@ trait Plugin {
}
fn post_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// List of what we modified that was valid?
_pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
_cand: &[Entry<EntrySealed, EntryCommitted>],
@ -81,7 +79,7 @@ trait Plugin {
}
fn pre_delete(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
_cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_de: &DeleteEvent,
) -> Result<(), OperationError> {
@ -90,7 +88,7 @@ trait Plugin {
}
fn post_delete(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// List of what we delete that was valid?
_cand: &[Entry<EntrySealed, EntryCommitted>],
_ce: &DeleteEvent,
@ -99,7 +97,7 @@ trait Plugin {
Err(OperationError::InvalidState)
}
fn verify(_qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
fn verify(_qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
admin_error!("plugin {} has an unimplemented verify!", Self::id());
vec![Err(ConsistencyError::Unknown)]
}
@ -121,7 +119,7 @@ macro_rules! run_verify_plugin {
impl Plugins {
#[instrument(level = "debug", name = "plugins::run_pre_create_transform", skip_all)]
pub fn run_pre_create_transform(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -137,7 +135,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_pre_create", skip_all)]
pub fn run_pre_create(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryNew>],
ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -146,7 +144,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_post_create", skip_all)]
pub fn run_post_create(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -156,7 +154,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_pre_modify", skip_all)]
pub fn run_pre_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
me: &ModifyEvent,
) -> Result<(), OperationError> {
@ -173,7 +171,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_post_modify", skip_all)]
pub fn run_post_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
cand: &[Entry<EntrySealed, EntryCommitted>],
me: &ModifyEvent,
@ -185,7 +183,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_pre_delete", skip_all)]
pub fn run_pre_delete(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
de: &DeleteEvent,
) -> Result<(), OperationError> {
@ -194,7 +192,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_post_delete", skip_all)]
pub fn run_post_delete(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
de: &DeleteEvent,
) -> Result<(), OperationError> {
@ -204,7 +202,7 @@ impl Plugins {
#[instrument(level = "debug", name = "plugins::run_verify", skip_all)]
pub fn run_verify(
qs: &QueryServerReadTransaction,
qs: &mut QueryServerReadTransaction,
results: &mut Vec<Result<(), ConsistencyError>>,
) {
run_verify_plugin!(qs, results, base::Base);

View file

@ -22,7 +22,7 @@ impl Plugin for PasswordImport {
skip(_qs, cand, _ce)
)]
fn pre_create_transform(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -70,7 +70,7 @@ impl Plugin for PasswordImport {
skip(_qs, cand, _me)
)]
fn pre_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {

View file

@ -39,7 +39,7 @@ impl Plugin for Protected {
#[instrument(level = "debug", name = "protected_pre_create", skip(_qs, cand, ce))]
fn pre_create(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// List of what we will commit that is valid?
cand: &[Entry<EntrySealed, EntryNew>],
ce: &CreateEvent,
@ -67,7 +67,7 @@ impl Plugin for Protected {
#[instrument(level = "debug", name = "protected_pre_modify", skip(_qs, cand, me))]
fn pre_modify(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// Should these be EntrySealed?
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
me: &ModifyEvent,
@ -138,7 +138,7 @@ impl Plugin for Protected {
#[instrument(level = "debug", name = "protected_pre_delete", skip(_qs, cand, de))]
fn pre_delete(
_qs: &QueryServerWriteTransaction,
_qs: &mut QueryServerWriteTransaction,
// Should these be EntrySealed
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
de: &DeleteEvent,

View file

@ -1,2 +0,0 @@
// Don't allow setting class = recycle/tombstone during any
// operation unless internal == true OR delete.

View file

@ -84,7 +84,7 @@ impl Plugin for ReferentialIntegrity {
// be in cand AND db" to simply "is it in the DB?".
#[instrument(level = "debug", name = "refint_post_create", skip(qs, cand, _ce))]
fn post_create(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -125,7 +125,7 @@ impl Plugin for ReferentialIntegrity {
skip(qs, _pre_cand, _cand, me)
)]
fn post_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
_pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
_cand: &[Entry<EntrySealed, EntryCommitted>],
me: &ModifyEvent,
@ -165,7 +165,7 @@ impl Plugin for ReferentialIntegrity {
#[instrument(level = "debug", name = "refint_post_delete", skip(qs, cand, _ce))]
fn post_delete(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &[Entry<EntrySealed, EntryCommitted>],
_ce: &DeleteEvent,
) -> Result<(), OperationError> {
@ -217,7 +217,7 @@ impl Plugin for ReferentialIntegrity {
}
#[instrument(level = "debug", name = "verify", skip(qs))]
fn verify(qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
// Get all entries as cand
// build a cand-uuid set
let filt_in = filter_all!(f_pres("class"));
@ -599,7 +599,7 @@ mod tests {
Value::new_refer_s("d2b496bd-8493-47b7-8142-f568b5cf47ee").unwrap()
)]),
None,
|qs: &QueryServerWriteTransaction| {
|qs: &mut QueryServerWriteTransaction| {
// Any pre_hooks we need. In this case, we need to trigger the delete of testgroup_a
let de_sin = unsafe {
crate::event::DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
@ -647,7 +647,7 @@ mod tests {
preload,
filter!(f_eq("name", PartialValue::new_iname("testgroup_a"))),
None,
|_qs: &QueryServerWriteTransaction| {}
|_qs: &mut QueryServerWriteTransaction| {}
);
}
@ -689,7 +689,7 @@ mod tests {
preload,
filter!(f_eq("name", PartialValue::new_iname("testgroup_b"))),
None,
|_qs: &QueryServerWriteTransaction| {}
|_qs: &mut QueryServerWriteTransaction| {}
);
}
@ -715,7 +715,7 @@ mod tests {
preload,
filter!(f_eq("name", PartialValue::new_iname("testgroup_b"))),
None,
|_qs: &QueryServerWriteTransaction| {}
|_qs: &mut QueryServerWriteTransaction| {}
);
}
@ -761,7 +761,7 @@ mod tests {
preload,
filter!(f_eq("name", PartialValue::new_iname("testgroup"))),
None,
|qs: &QueryServerWriteTransaction| {
|qs: &mut QueryServerWriteTransaction| {
let cands = qs
.internal_search(filter!(f_eq(
"oauth2_rs_name",

View file

@ -25,7 +25,7 @@ impl Plugin for Spn {
skip(qs, cand, _ce)
)]
fn pre_create_transform(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
_ce: &CreateEvent,
) -> Result<(), OperationError> {
@ -60,7 +60,7 @@ impl Plugin for Spn {
#[instrument(level = "debug", name = "spn_pre_modify", skip(qs, cand, _me))]
fn pre_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
_me: &ModifyEvent,
) -> Result<(), OperationError> {
@ -95,7 +95,7 @@ impl Plugin for Spn {
skip(qs, pre_cand, cand, _ce)
)]
fn post_modify(
qs: &QueryServerWriteTransaction,
qs: &mut QueryServerWriteTransaction,
// List of what we modified that was valid?
pre_cand: &[Arc<Entry<EntrySealed, EntryCommitted>>],
cand: &[Entry<EntrySealed, EntryCommitted>],
@ -138,7 +138,7 @@ impl Plugin for Spn {
}
#[instrument(level = "debug", name = "spn_verify", skip(qs))]
fn verify(qs: &QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
// Verify that all items with spn's have valid spns.
// We need to consider the case that an item has a different origin domain too,
// so we should be able to verify that *those* spns validate to the trusted domain info
@ -313,42 +313,40 @@ mod tests {
);
}
#[test]
fn test_spn_regen_domain_rename() {
run_test!(|server: &QueryServer| {
let server_txn = server.write(duration_from_epoch_now());
#[qs_test]
async fn test_spn_regen_domain_rename(server: &QueryServer) {
let mut server_txn = server.write(duration_from_epoch_now()).await;
let ex1 = Value::new_spn_str("admin", "example.com");
let ex2 = Value::new_spn_str("admin", "new.example.com");
// get the current domain name
// check the spn on admin is admin@<initial domain>
let e_pre = server_txn
.internal_search_uuid(&UUID_ADMIN)
.expect("must not fail");
let ex1 = Value::new_spn_str("admin", "example.com");
let ex2 = Value::new_spn_str("admin", "new.example.com");
// get the current domain name
// check the spn on admin is admin@<initial domain>
let e_pre = server_txn
.internal_search_uuid(&UUID_ADMIN)
.expect("must not fail");
let e_pre_spn = e_pre.get_ava_single("spn").expect("must not fail");
assert!(e_pre_spn == ex1);
let e_pre_spn = e_pre.get_ava_single("spn").expect("must not fail");
assert!(e_pre_spn == ex1);
// trigger the domain_name change (this will be a cli option to the server
// in the final version), but it will still call the same qs function to perform the
// change.
unsafe {
server_txn
.domain_rename_inner("new.example.com")
.expect("should not fail!");
}
// trigger the domain_name change (this will be a cli option to the server
// in the final version), but it will still call the same qs function to perform the
// change.
unsafe {
server_txn
.domain_rename_inner("new.example.com")
.expect("should not fail!");
}
// check the spn on admin is admin@<new domain>
let e_post = server_txn
.internal_search_uuid(&UUID_ADMIN)
.expect("must not fail");
// check the spn on admin is admin@<new domain>
let e_post = server_txn
.internal_search_uuid(&UUID_ADMIN)
.expect("must not fail");
let e_post_spn = e_post.get_ava_single("spn").expect("must not fail");
debug!("{:?}", e_post_spn);
debug!("{:?}", ex2);
assert!(e_post_spn == ex2);
let e_post_spn = e_post.get_ava_single("spn").expect("must not fail");
debug!("{:?}", e_post_spn);
debug!("{:?}", ex2);
assert!(e_post_spn == ex2);
server_txn.commit().expect("Must not fail");
});
server_txn.commit().expect("Must not fail");
}
}

View file

@ -1672,9 +1672,8 @@ mod tests {
#[test]
fn test_schema_attribute_from_entry() {
run_test!(|_qs: &QueryServer| {
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1682,11 +1681,11 @@ mod tests {
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
}
}"#,
SchemaAttribute
);
SchemaAttribute
);
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1697,11 +1696,11 @@ mod tests {
"syntax": ["UTF8STRING"]
}
}"#,
SchemaAttribute
);
SchemaAttribute
);
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1713,11 +1712,11 @@ mod tests {
"syntax": ["UTF8STRING"]
}
}"#,
SchemaAttribute
);
SchemaAttribute
);
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1729,11 +1728,11 @@ mod tests {
"syntax": ["UTF8STRING"]
}
}"#,
SchemaAttribute
);
SchemaAttribute
);
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1745,12 +1744,12 @@ mod tests {
"syntax": ["TNEOUNTUH"]
}
}"#,
SchemaAttribute
);
SchemaAttribute
);
// Index is allowed to be empty
sch_from_entry_ok!(
r#"{
// Index is allowed to be empty
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1761,12 +1760,12 @@ mod tests {
"syntax": ["UTF8STRING"]
}
}"#,
SchemaAttribute
);
SchemaAttribute
);
// Index present
sch_from_entry_ok!(
r#"{
// Index present
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "attributetype"],
"attributename": ["schema_attr_test"],
@ -1778,27 +1777,25 @@ mod tests {
"syntax": ["UTF8STRING"]
}
}"#,
SchemaAttribute
);
});
SchemaAttribute
);
}
#[test]
fn test_schema_class_from_entry() {
run_test!(|_qs: &QueryServer| {
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object", "classtype"],
"classname": ["schema_class_test"],
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
}
}"#,
SchemaClass
);
SchemaClass
);
sch_from_entry_err!(
r#"{
sch_from_entry_err!(
r#"{
"attrs": {
"class": ["object"],
"classname": ["schema_class_test"],
@ -1806,12 +1803,12 @@ mod tests {
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
}
}"#,
SchemaClass
);
SchemaClass
);
// Classes can be valid with no attributes provided.
sch_from_entry_ok!(
r#"{
// Classes can be valid with no attributes provided.
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "classtype"],
"classname": ["schema_class_test"],
@ -1819,12 +1816,12 @@ mod tests {
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
}
}"#,
SchemaClass
);
SchemaClass
);
// Classes with various may/must
sch_from_entry_ok!(
r#"{
// Classes with various may/must
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "classtype"],
"classname": ["schema_class_test"],
@ -1833,11 +1830,11 @@ mod tests {
"systemmust": ["d"]
}
}"#,
SchemaClass
);
SchemaClass
);
sch_from_entry_ok!(
r#"{
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "classtype"],
"classname": ["schema_class_test"],
@ -1846,11 +1843,11 @@ mod tests {
"systemmay": ["c"]
}
}"#,
SchemaClass
);
SchemaClass
);
sch_from_entry_ok!(
r#"{
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "classtype"],
"classname": ["schema_class_test"],
@ -1860,11 +1857,11 @@ mod tests {
"must": ["b"]
}
}"#,
SchemaClass
);
SchemaClass
);
sch_from_entry_ok!(
r#"{
sch_from_entry_ok!(
r#"{
"attrs": {
"class": ["object", "classtype"],
"classname": ["schema_class_test"],
@ -1876,9 +1873,8 @@ mod tests {
"systemmust": ["d"]
}
}"#,
SchemaClass
);
});
SchemaClass
);
}
#[test]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
use crate::be::{Backend, BackendConfig};
use crate::prelude::*;
use crate::schema::Schema;
#[allow(unused_imports)]
use crate::utils::duration_from_epoch_now;
pub async fn setup_test() -> QueryServer {
let _ = sketching::test_init();
// Create an in memory BE
let schema_outer = Schema::new().expect("Failed to init schema");
let idxmeta = {
let schema_txn = schema_outer.write();
schema_txn.reload_idxmeta()
};
let be = Backend::new(BackendConfig::new_test(), idxmeta, false).expect("Failed to init BE");
let qs = QueryServer::new(be, schema_outer, "example.com".to_string());
// Init is called via the proc macro
qs
}

View file

@ -0,0 +1,14 @@
[package]
name = "testkit-macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
proc-macro2.workspace = true
quote.workspace = true
syn.workspace = true

View file

@ -0,0 +1,88 @@
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use syn::spanned::Spanned;
use quote::{quote, quote_spanned, ToTokens};
fn parse_knobs(input: syn::ItemFn) -> TokenStream {
// If type mismatch occurs, the current rustc points to the last statement.
let (last_stmt_start_span, _last_stmt_end_span) = {
let mut last_stmt = input
.block
.stmts
.last()
.map(ToTokens::into_token_stream)
.unwrap_or_default()
.into_iter();
// `Span` on stable Rust has a limitation that only points to the first
// token, not the whole tokens. We can work around this limitation by
// using the first/last span of the tokens like
// `syn::Error::new_spanned` does.
let start = last_stmt.next().map_or_else(Span::call_site, |t| t.span());
let end = last_stmt.last().map_or(start, |t| t.span());
(start, end)
};
let rt = quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
};
let header = quote! {
#[::core::prelude::v1::test]
};
let fn_name = &input.sig.ident;
let test_driver = Ident::new(&format!("tk_{}", fn_name), input.sig.span());
// Effectively we are just injecting a real test function around this which we will
// call.
let result = quote! {
#input
#header
fn #test_driver() {
let body = async {
let rsclient = kanidmd_testkit::setup_async_test().await;
#fn_name(rsclient).await
};
#[allow(clippy::expect_used, clippy::diverging_sub_expression)]
{
return #rt
.enable_all()
.build()
.expect("Failed building the Runtime")
.block_on(body);
}
}
};
result.into()
}
fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream {
tokens.extend(TokenStream::from(error.into_compile_error()));
tokens
}
pub(crate) fn test(_args: TokenStream, item: TokenStream) -> TokenStream {
// If any of the steps for this macro fail, we still want to expand to an item that is as close
// to the expected output as possible. This helps out IDEs such that completions and other
// related features keep working.
let input: syn::ItemFn = match syn::parse(item.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(item, e),
};
if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) {
let msg = "second test attribute is supplied";
return token_stream_with_error(item, syn::Error::new_spanned(&attr, msg));
};
if input.sig.asyncness.is_none() {
let msg = "the `async` keyword is missing from the function declaration";
return token_stream_with_error(item, syn::Error::new_spanned(input.sig.fn_token, msg));
}
parse_knobs(input)
}

View file

@ -0,0 +1,23 @@
#![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
mod entry;
#[allow(unused_extern_crates)]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
entry::test(args, item)
}

View file

@ -0,0 +1,41 @@
[package]
name = "kanidmd_testkit"
description = "Kanidm Server Test Framework"
documentation = "https://docs.rs/kanidm/latest/kanidm/"
version.workspace = true
authors.workspace = true
rust-version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
[lib]
name = "kanidmd_testkit"
path = "src/lib.rs"
[dependencies]
kanidm_client.workspace = true
kanidm_proto.workspace = true
kanidmd_core.workspace = true
kanidmd_lib.workspace = true
futures.workspace = true
webauthn-authenticator-rs.workspace = true
oauth2_ext = { workspace = true, default-features = false }
url = { workspace = true, features = ["serde"] }
reqwest = { workspace = true, features=["cookies", "json", "native-tls"] }
sketching.workspace = true
testkit-macros.workspace = true
tracing = { workspace = true, features = ["attributes"] }
tokio = { workspace = true, features = ["net", "sync", "io-util", "macros"] }
[build-dependencies]
profiles.workspace = true
[dev-dependencies]
compact_jwt.workspace = true
serde_json.workspace = true

3
kanidmd/testkit/build.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
profiles::apply_profile();
}

View file

@ -1,3 +1,15 @@
#![deny(warnings)]
#![warn(unused_extern_crates)]
#![deny(clippy::todo)]
#![deny(clippy::unimplemented)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
#![deny(clippy::panic)]
#![deny(clippy::unreachable)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
use std::net::TcpStream;
use std::sync::atomic::{AtomicU16, Ordering};
@ -10,6 +22,8 @@ pub const ADMIN_TEST_USER: &str = "admin";
pub const ADMIN_TEST_PASSWORD: &str = "integration test admin password";
pub static PORT_ALLOC: AtomicU16 = AtomicU16::new(18080);
pub use testkit_macros::test;
pub fn is_free_port(port: u16) -> bool {
// TODO: Refactor to use `Result::is_err` in a future PR
match TcpStream::connect(("0.0.0.0", port)) {
@ -50,7 +64,7 @@ pub async fn setup_async_test() -> KanidmClient {
config.address = format!("127.0.0.1:{}", port);
config.secure_cookies = false;
config.integration_test_config = Some(int_config);
config.role = ServerRole::WriteReplicaNoUI;
config.role = ServerRole::WriteReplica;
config.domain = "localhost".to_string();
config.origin = addr.clone();
// config.log_level = Some(LogLevel::Verbose as u32);
@ -64,10 +78,12 @@ pub async fn setup_async_test() -> KanidmClient {
task::yield_now().await;
let rsclient = KanidmClientBuilder::new()
.address(addr)
.address(addr.clone())
.no_proxy()
.build()
.expect("Failed to build client");
tracing::info!("Testkit server setup complete - {}", addr);
rsclient
}

View file

@ -4,8 +4,7 @@ use std::collections::HashSet;
use kanidm_client::KanidmClient;
use kanidm_proto::v1::{Filter, Modify, ModifyList};
mod common;
use crate::common::{setup_async_test, ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
use kanidmd_testkit::{ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
static USER_READABLE_ATTRS: [&str; 9] = [
"name",
@ -286,9 +285,8 @@ async fn test_modify_group(
// - Read to all self attributes (within security constraints).
// - Write to a limited set of self attributes, such as:
// name, displayname, legalname, ssh-keys, credentials etc.
#[tokio::test]
async fn test_default_entries_rbac_users() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_users(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -327,9 +325,8 @@ async fn test_default_entries_rbac_users() {
// Account Managers
// read and write to accounts, including write credentials but NOT private data (see people manager)
// ability to lock and unlock accounts, excluding high access members.
#[tokio::test]
async fn test_default_entries_rbac_account_managers() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_account_managers(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -363,9 +360,8 @@ async fn test_default_entries_rbac_account_managers() {
// Group Managers
// read all groups
// write group but not high access
#[tokio::test]
async fn test_default_entries_rbac_group_managers() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_group_managers(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -411,9 +407,8 @@ async fn test_default_entries_rbac_group_managers() {
// Admins
// read and write access control entries.
#[tokio::test]
async fn test_default_entries_rbac_admins_access_control_entries() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_access_control_entries(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -463,9 +458,8 @@ async fn test_default_entries_rbac_admins_access_control_entries() {
// read schema entries.
// TODO #252: write schema entries
#[tokio::test]
async fn test_default_entries_rbac_admins_schema_entries() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_schema_entries(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -579,9 +573,8 @@ async fn test_default_entries_rbac_admins_schema_entries() {
// modify all groups including high access groups.
// create new accounts (to bootstrap the system).
#[tokio::test]
async fn test_default_entries_rbac_admins_group_entries() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_group_entries(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -600,9 +593,8 @@ async fn test_default_entries_rbac_admins_group_entries() {
}
// modify high access accounts as an escalation for security sensitive accounts.
#[tokio::test]
async fn test_default_entries_rbac_admins_ha_accounts() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_ha_accounts(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -617,9 +609,8 @@ async fn test_default_entries_rbac_admins_ha_accounts() {
}
// recover from the recycle bin
#[tokio::test]
async fn test_default_entries_rbac_admins_recycle_accounts() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_admins_recycle_accounts(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -641,9 +632,8 @@ async fn test_default_entries_rbac_admins_recycle_accounts() {
// People Managers
// read private or sensitive data of persons, IE legalName
// write private or sensitive data of persons, IE legalName
#[tokio::test]
async fn test_default_entries_rbac_people_managers() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_people_managers(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -684,9 +674,8 @@ async fn test_default_entries_rbac_people_managers() {
// Anonymous Clients + Everyone Else
// read memberof, unix attrs, name, displayname, class
#[tokio::test]
async fn test_default_entries_rbac_anonymous_entry() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_anonymous_entry(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -715,9 +704,8 @@ async fn test_default_entries_rbac_anonymous_entry() {
// RADIUS Servers
// Read radius credentials
// Read other needed attributes to fulfil radius functions.
#[tokio::test]
async fn test_default_entries_rbac_radius_servers() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_default_entries_rbac_radius_servers(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -738,9 +726,8 @@ async fn test_default_entries_rbac_radius_servers() {
test_write_attrs(&rsclient, "test", &RADIUS_NECESSARY_ATTRS, false).await;
}
#[tokio::test]
async fn test_self_write_mail_priv_people() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_self_write_mail_priv_people(rsclient: KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await

View file

@ -0,0 +1,39 @@
use kanidm_client::KanidmClient;
#[kanidmd_testkit::test]
async fn test_https_middleware_headers(rsclient: KanidmClient) {
// We need to do manual reqwests here.
let addr = rsclient.get_url();
// here we test the /ui/ endpoint which should have the headers
let response = match reqwest::get(format!("{}/ui/", &addr)).await {
Ok(value) => value,
Err(error) => {
panic!("Failed to query {:?} : {:#?}", addr, error);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 200);
eprintln!(
"csp headers: {:#?}",
response.headers().get("content-security-policy")
);
assert_ne!(response.headers().get("content-security-policy"), None);
// here we test the /pkg/ endpoint which shouldn't have the headers
let response =
match reqwest::get(format!("{}/pkg/external/bootstrap.bundle.min.js", &addr)).await {
Ok(value) => value,
Err(error) => {
panic!("Failed to query {:?} : {:#?}", addr, error);
}
};
eprintln!("response: {:#?}", response);
assert_eq!(response.status(), 200);
eprintln!(
"csp headers: {:#?}",
response.headers().get("content-security-policy")
);
assert_eq!(response.headers().get("content-security-policy"), None);
}

View file

@ -1,5 +1,4 @@
#![deny(warnings)]
mod common;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::str::FromStr;
@ -12,7 +11,8 @@ use kanidm_proto::oauth2::{
use oauth2_ext::PkceCodeChallenge;
use url::Url;
use crate::common::{setup_async_test, ADMIN_TEST_PASSWORD};
use kanidm_client::KanidmClient;
use kanidmd_testkit::ADMIN_TEST_PASSWORD;
macro_rules! assert_no_cache {
($response:expr) => {{
@ -38,9 +38,8 @@ macro_rules! assert_no_cache {
}};
}
#[tokio::test]
async fn test_oauth2_openid_basic_flow() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_oauth2_openid_basic_flow(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;

View file

@ -7,20 +7,19 @@ use kanidm_proto::v1::{
use kanidmd_lib::credential::totp::Totp;
use tracing::debug;
mod common;
use std::str::FromStr;
use compact_jwt::JwsUnverified;
use webauthn_authenticator_rs::softpasskey::SoftPasskey;
use webauthn_authenticator_rs::WebauthnAuthenticator;
use crate::common::{setup_async_test, ADMIN_TEST_PASSWORD};
use kanidm_client::KanidmClient;
use kanidmd_testkit::ADMIN_TEST_PASSWORD;
const UNIX_TEST_PASSWORD: &str = "unix test user password";
#[tokio::test]
async fn test_server_create() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_create(rsclient: KanidmClient) {
let e: Entry = serde_json::from_str(
r#"{
"attrs": {
@ -45,11 +44,9 @@ async fn test_server_create() {
assert!(res.is_ok());
}
#[tokio::test]
async fn test_server_modify() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_modify(rsclient: KanidmClient) {
// Build a self mod.
let f = Filter::SelfUuid;
let m = ModifyList::new_list(vec![
Modify::Purged("displayname".to_string()),
@ -70,9 +67,8 @@ async fn test_server_modify() {
assert!(res.is_ok());
}
#[tokio::test]
async fn test_server_whoami_anonymous() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_whoami_anonymous(rsclient: KanidmClient) {
// First show we are un-authenticated.
let pre_res = rsclient.whoami().await;
// This means it was okay whoami, but no uat attached.
@ -97,9 +93,8 @@ async fn test_server_whoami_anonymous() {
assert!(res.is_ok());
}
#[tokio::test]
async fn test_server_whoami_admin_simple_password() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_whoami_admin_simple_password(rsclient: KanidmClient) {
// First show we are un-authenticated.
let pre_res = rsclient.whoami().await;
// This means it was okay whoami, but no uat attached.
@ -120,9 +115,8 @@ async fn test_server_whoami_admin_simple_password() {
assert!(e.attrs.get("spn") == Some(&vec!["admin@localhost".to_string()]));
}
#[tokio::test]
async fn test_server_search() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_search(rsclient: KanidmClient) {
// First show we are un-authenticated.
let pre_res = rsclient.whoami().await;
// This means it was okay whoami, but no uat attached.
@ -146,9 +140,8 @@ async fn test_server_search() {
}
// test the rest group endpoint.
#[tokio::test]
async fn test_server_rest_group_read() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_group_read(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -163,9 +156,8 @@ async fn test_server_rest_group_read() {
println!("{:?}", g);
}
#[tokio::test]
async fn test_server_rest_group_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -238,9 +230,8 @@ async fn test_server_rest_group_lifecycle() {
assert!(members == Some(vec!["idm_admin@localhost".to_string()]));
}
#[tokio::test]
async fn test_server_rest_account_read() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_account_read(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -255,9 +246,8 @@ async fn test_server_rest_account_read() {
println!("{:?}", a);
}
#[tokio::test]
async fn test_server_rest_schema_read() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_schema_read(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -284,9 +274,8 @@ async fn test_server_rest_schema_read() {
}
// Test resetting a radius cred, and then checking/viewing it.
#[tokio::test]
async fn test_server_radius_credential_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_radius_credential_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -356,9 +345,8 @@ async fn test_server_radius_credential_lifecycle() {
assert!(n_sec.is_none());
}
#[tokio::test]
async fn test_server_rest_person_account_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_person_account_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -408,9 +396,8 @@ async fn test_server_rest_person_account_lifecycle() {
.unwrap();
}
#[tokio::test]
async fn test_server_rest_sshkey_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_sshkey_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -466,9 +453,8 @@ async fn test_server_rest_sshkey_lifecycle() {
assert!(skn.unwrap() == Some("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBx4TpJYQjd0YI5lQIHqblIsCIK5NKVFURYS/eM3o6/Z william@amethyst".to_string()));
}
#[tokio::test]
async fn test_server_rest_domain_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_domain_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -497,9 +483,8 @@ async fn test_server_rest_domain_lifecycle() {
);
}
#[tokio::test]
async fn test_server_rest_posix_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_posix_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -594,9 +579,8 @@ async fn test_server_rest_posix_lifecycle() {
assert!(r3.name == "posix_group");
}
#[tokio::test]
async fn test_server_rest_posix_auth_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_posix_auth_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -667,9 +651,8 @@ async fn test_server_rest_posix_auth_lifecycle() {
};
}
#[tokio::test]
async fn test_server_rest_recycle_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_recycle_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -722,9 +705,8 @@ async fn test_server_rest_recycle_lifecycle() {
assert!(acc.is_some());
}
#[tokio::test]
async fn test_server_rest_account_import_password() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_account_import_password(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -784,9 +766,8 @@ async fn test_server_rest_account_import_password() {
}
}
#[tokio::test]
async fn test_server_rest_oauth2_basic_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -922,9 +903,8 @@ async fn test_server_rest_oauth2_basic_lifecycle() {
assert!(final_configs.is_empty());
}
#[tokio::test]
async fn test_server_credential_update_session_pw() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_pw(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -981,9 +961,8 @@ async fn test_server_credential_update_session_pw() {
assert!(res.is_ok());
}
#[tokio::test]
async fn test_server_credential_update_session_totp_pw() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_totp_pw(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -1099,9 +1078,8 @@ async fn test_server_credential_update_session_totp_pw() {
assert!(res.is_ok());
}
#[tokio::test]
async fn test_server_credential_update_session_passkey() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_passkey(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -1188,9 +1166,8 @@ async fn test_server_credential_update_session_passkey() {
assert!(res.is_ok());
}
#[tokio::test]
async fn test_server_api_token_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -1247,9 +1224,8 @@ async fn test_server_api_token_lifecycle() {
// No need to test expiry, that's validated in the server internal tests.
}
#[tokio::test]
async fn test_server_user_auth_token_lifecycle() {
let rsclient = setup_async_test().await;
#[kanidmd_testkit::test]
async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;

View file

@ -2,6 +2,8 @@
name = "profiles"
description = "Kanidm Build System Profiles"
documentation = "https://docs.rs/kanidm/latest/kanidm/"
# We do not have tests in this pkg
autotests = false
version.workspace = true
authors.workspace = true

View file

@ -1,5 +1,7 @@
[package]
name = "sketching"
# We do not have tests in this pkg
autotests = false
version.workspace = true
authors.workspace = true