mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
20221022 improve test macros (#1139)
This commit is contained in:
parent
17774cb3bb
commit
c4ecdf4447
52
Cargo.lock
generated
52
Cargo.lock
generated
|
@ -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"
|
||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -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"
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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),
|
||||
|
|
13
kanidmd/lib-macros/Cargo.toml
Normal file
13
kanidmd/lib-macros/Cargo.toml
Normal 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
|
||||
|
99
kanidmd/lib-macros/src/entry.rs
Normal file
99
kanidmd/lib-macros/src/entry.rs
Normal 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()
|
||||
}
|
28
kanidmd/lib-macros/src/lib.rs
Normal file
28
kanidmd/lib-macros/src/lib.rs
Normal 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)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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::*;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}};
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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![]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
|
@ -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> {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
// Don't allow setting class = recycle/tombstone during any
|
||||
// operation unless internal == true OR delete.
|
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
21
kanidmd/lib/src/testkit.rs
Normal file
21
kanidmd/lib/src/testkit.rs
Normal 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
|
||||
}
|
14
kanidmd/testkit-macros/Cargo.toml
Normal file
14
kanidmd/testkit-macros/Cargo.toml
Normal 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
|
||||
|
||||
|
88
kanidmd/testkit-macros/src/entry.rs
Normal file
88
kanidmd/testkit-macros/src/entry.rs
Normal 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)
|
||||
}
|
23
kanidmd/testkit-macros/src/lib.rs
Normal file
23
kanidmd/testkit-macros/src/lib.rs
Normal 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)
|
||||
}
|
41
kanidmd/testkit/Cargo.toml
Normal file
41
kanidmd/testkit/Cargo.toml
Normal 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
3
kanidmd/testkit/build.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
fn main() {
|
||||
profiles::apply_profile();
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
39
kanidmd/testkit/tests/https_middleware.rs
Normal file
39
kanidmd/testkit/tests/https_middleware.rs
Normal 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);
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
[package]
|
||||
name = "sketching"
|
||||
# We do not have tests in this pkg
|
||||
autotests = false
|
||||
|
||||
version.workspace = true
|
||||
authors.workspace = true
|
||||
|
|
Loading…
Reference in a new issue