20250225 ldap testing in testkit ()

Add support for ldap servers in integration tests

This allows the ldap interface to be enabled during tests, which is
a final requirement to complete ldap application passwords.
This commit is contained in:
Firstyear 2025-03-11 12:35:31 +10:00 committed by GitHub
parent 23d35dc324
commit 919e0ba6fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 344 additions and 236 deletions

1
Cargo.lock generated
View file

@ -3254,6 +3254,7 @@ dependencies = [
"kanidm_proto",
"kanidmd_core",
"kanidmd_lib",
"ldap3_client",
"oauth2 4.4.2",
"openssl",
"petgraph",

View file

@ -1,8 +1,5 @@
use std::net;
use std::pin::Pin;
use std::str::FromStr;
use crate::actors::QueryServerReadV1;
use crate::CoreAction;
use futures_util::sink::SinkExt;
use futures_util::stream::StreamExt;
use kanidmd_lib::idm::ldap::{LdapBoundToken, LdapResponseState};
@ -10,13 +7,15 @@ use kanidmd_lib::prelude::*;
use ldap3_proto::proto::LdapMsg;
use ldap3_proto::LdapCodec;
use openssl::ssl::{Ssl, SslAcceptor};
use std::net;
use std::pin::Pin;
use std::str::FromStr;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::net::{TcpListener, TcpStream};
use tokio_openssl::SslStream;
use tokio_util::codec::{FramedRead, FramedWrite};
use crate::CoreAction;
use tokio::sync::broadcast;
use tokio::sync::mpsc;
use tokio_openssl::SslStream;
use tokio_util::codec::{FramedRead, FramedWrite};
struct LdapSession {
uat: Option<LdapBoundToken>,
@ -49,28 +48,14 @@ async fn client_process_msg(
.await
}
async fn client_process(
tcpstream: TcpStream,
tls_acceptor: SslAcceptor,
async fn client_process<STREAM>(
stream: STREAM,
client_address: net::SocketAddr,
qe_r_ref: &'static QueryServerReadV1,
) {
// Start the event
// From the parameters we need to create an SslContext.
let mut tlsstream = match Ssl::new(tls_acceptor.context())
.and_then(|tls_obj| SslStream::new(tls_obj, tcpstream))
{
Ok(ta) => ta,
Err(e) => {
error!("LDAP TLS setup error, continuing -> {:?}", e);
return;
}
};
if let Err(e) = SslStream::accept(Pin::new(&mut tlsstream)).await {
error!("LDAP TLS accept error, continuing -> {:?}", e);
return;
};
let (r, w) = tokio::io::split(tlsstream);
) where
STREAM: AsyncRead + AsyncWrite,
{
let (r, w) = tokio::io::split(stream);
let mut r = FramedRead::new(r, LdapCodec::default());
let mut w = FramedWrite::new(w, LdapCodec::default());
@ -126,7 +111,32 @@ async fn client_process(
}
}
/// TLS LDAP Listener, hands off to [client_process]
async fn client_tls_accept(
tcpstream: TcpStream,
tls_acceptor: SslAcceptor,
client_socket_addr: net::SocketAddr,
qe_r_ref: &'static QueryServerReadV1,
) {
// Start the event
// From the parameters we need to create an SslContext.
let mut tlsstream = match Ssl::new(tls_acceptor.context())
.and_then(|tls_obj| SslStream::new(tls_obj, tcpstream))
{
Ok(ta) => ta,
Err(err) => {
error!(?err, %client_socket_addr, "LDAP TLS setup error");
return;
}
};
if let Err(err) = SslStream::accept(Pin::new(&mut tlsstream)).await {
error!(?err, %client_socket_addr, "LDAP TLS accept error");
return;
};
tokio::spawn(client_process(tlsstream, client_socket_addr, qe_r_ref));
}
/// TLS LDAP Listener, hands off to [client_tls_accept]
async fn ldap_tls_acceptor(
listener: TcpListener,
mut tls_acceptor: SslAcceptor,
@ -145,10 +155,10 @@ async fn ldap_tls_acceptor(
match accept_result {
Ok((tcpstream, client_socket_addr)) => {
let clone_tls_acceptor = tls_acceptor.clone();
tokio::spawn(client_process(tcpstream, clone_tls_acceptor, client_socket_addr, qe_r_ref));
tokio::spawn(client_tls_accept(tcpstream, clone_tls_acceptor, client_socket_addr, qe_r_ref));
}
Err(e) => {
error!("LDAP acceptor error, continuing -> {:?}", e);
Err(err) => {
warn!(?err, "LDAP acceptor error, continuing");
}
}
}
@ -161,6 +171,34 @@ async fn ldap_tls_acceptor(
info!("Stopped {}", super::TaskName::LdapActor);
}
/// PLAIN LDAP Listener, hands off to [client_process]
async fn ldap_plaintext_acceptor(
listener: TcpListener,
qe_r_ref: &'static QueryServerReadV1,
mut rx: broadcast::Receiver<CoreAction>,
) {
loop {
tokio::select! {
Ok(action) = rx.recv() => {
match action {
CoreAction::Shutdown => break,
}
}
accept_result = listener.accept() => {
match accept_result {
Ok((tcpstream, client_socket_addr)) => {
tokio::spawn(client_process(tcpstream, client_socket_addr, qe_r_ref));
}
Err(e) => {
error!("LDAP acceptor error, continuing -> {:?}", e);
}
}
}
}
}
info!("Stopped {}", super::TaskName::LdapActor);
}
pub(crate) async fn create_ldap_server(
address: &str,
opt_ssl_acceptor: Option<SslAcceptor>,
@ -197,10 +235,7 @@ pub(crate) async fn create_ldap_server(
tls_acceptor_reload_rx,
))
}
None => {
error!("The server won't run without TLS!");
return Err(());
}
None => tokio::spawn(ldap_plaintext_acceptor(listener, qe_r_ref, rx)),
};
info!("Created LDAP interface");

View file

@ -1080,20 +1080,15 @@ pub async fn create_server_core(
Some(la) => {
let opt_ldap_ssl_acceptor = maybe_tls_acceptor.clone();
if !config_test {
// ⚠️ only start the sockets and listeners in non-config-test modes.
let h = ldaps::create_ldap_server(
la.as_str(),
opt_ldap_ssl_acceptor,
server_read_ref,
broadcast_tx.subscribe(),
ldap_tls_acceptor_reload_rx,
)
.await?;
Some(h)
} else {
None
}
let h = ldaps::create_ldap_server(
la.as_str(),
opt_ldap_ssl_acceptor,
server_read_ref,
broadcast_tx.subscribe(),
ldap_tls_acceptor_reload_rx,
)
.await?;
Some(h)
}
None => {
debug!("LDAP not requested, skipping");

View file

@ -34,7 +34,7 @@ fn parse_attributes(
});
if !args_are_allowed {
let msg = "Invalid test config attribute. The following are allow";
let msg = "Invalid test config attribute. The following are allowed";
return Err(syn::Error::new_spanned(
input.sig.fn_token,
format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),

View file

@ -205,7 +205,7 @@ pub(crate) trait IdlSqliteTransaction {
let mut stmt = self
.get_conn()?
.prepare(&format!(
"SELECT rowid from {}.sqlite_master where name = :tname LIMIT 1",
"SELECT rowid from {}.sqlite_master where type=\"table\" AND name = :tname LIMIT 1",
self.get_db_name()
))
.map_err(sqlite_error)?;

View file

@ -14,87 +14,73 @@ const ALLOWED_ATTRIBUTES: &[&str] = &[
"role",
"output_mode",
"log_level",
"ldap",
];
fn parse_knobs(
input: &syn::ItemFn,
server_config: &Punctuated<ExprAssign, syn::token::Comma>,
) -> 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)
};
#[derive(Default)]
struct Flags {
ldap: bool,
}
// here we gather all the provided configuration in a struct like declaration
// By now we have already checked that the configurations provided belong to the allowed subset
let mut field_modifications = quote! {};
server_config.pairs().for_each(|p| {
let field_name = p.value().left.to_token_stream(); // here we can use to_token_stream as we know we're iterating over ExprAssigns
let field_value = p.value().right.to_token_stream();
field_modifications.extend(quote! {
#field_name: #field_value,})
fn parse_attributes(
args: &TokenStream,
input: &syn::ItemFn,
) -> Result<(proc_macro2::TokenStream, Flags), syn::Error> {
let args: Punctuated<ExprAssign, syn::token::Comma> =
Punctuated::<ExprAssign, Token![,]>::parse_terminated.parse(args.clone())?;
let args_are_allowed = args.pairs().all(|p| {
ALLOWED_ATTRIBUTES.to_vec().contains(
&p.value()
.left
.span()
.source_text()
.unwrap_or_default()
.as_str(),
)
});
// Setup the config filling the remaining fields with the default values
let default_config_struct = quote!(kanidmd_core::config::Configuration {
if !args_are_allowed {
let msg = "Invalid test config attribute. The following are allowed";
return Err(syn::Error::new_spanned(
input.sig.fn_token,
format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),
));
}
let mut flags = Flags::default();
let mut field_modifications = quote! {};
args.pairs().for_each(|p| {
match p
.value()
.left
.span()
.source_text()
.unwrap_or_default()
.as_str()
{
"ldap" => {
flags.ldap = true;
field_modifications.extend(quote! {
ldapaddress: Some("on".to_string()),})
}
_ => {
let field_name = p.value().left.to_token_stream(); // here we can use to_token_stream as we know we're iterating over ExprAssigns
let field_value = p.value().right.to_token_stream();
// This is printing out struct members.
field_modifications.extend(quote! {
#field_name: #field_value,})
}
}
});
let ts = quote!(kanidmd_core::config::Configuration {
#field_modifications
..kanidmd_core::config::Configuration::new_for_test()
});
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, mut core_handle) = kanidmd_testkit::setup_async_test(#default_config_struct).await;
#fn_name(rsclient).await;
core_handle.shutdown().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
Ok((ts, flags))
}
pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
@ -115,31 +101,80 @@ pub(crate) fn test(args: TokenStream, item: TokenStream) -> TokenStream {
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));
}
let args: Punctuated<ExprAssign, syn::token::Comma> =
match Punctuated::<ExprAssign, Token![,]>::parse_terminated.parse(args.clone()) {
Ok(it) => it,
Err(e) => return token_stream_with_error(args, e),
};
let args_are_allowed = args.pairs().all(|p| {
ALLOWED_ATTRIBUTES.to_vec().contains(
&p.value()
.left
.span()
.source_text()
.unwrap_or_default()
.as_str(),
)
});
if !args_are_allowed {
let msg =
"Currently only a subset of all the server configs can be set. Here is the full list";
return token_stream_with_error(
item,
syn::Error::new_spanned(
input.sig.fn_token,
format!("{}: {}", msg, ALLOWED_ATTRIBUTES.join(", ")),
),
);
}
parse_knobs(&input, &args)
// 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)
};
// Setup the config filling the remaining fields with the default values
let (default_config_struct, flags) = match parse_attributes(&args, &input) {
Ok(dc) => dc,
Err(e) => return token_stream_with_error(args, e),
};
let rt = quote_spanned! {last_stmt_start_span=>
tokio::runtime::Builder::new_current_thread()
};
let header = quote! {
#[::core::prelude::v1::test]
};
let test_fn_args = if flags.ldap {
quote! {
&test_env
}
} else {
quote! {
&test_env.rsclient
}
};
let test_fn = &input.sig.ident;
let test_driver = Ident::new(&format!("tk_{}", 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 mut test_env = kanidmd_testkit::setup_async_test(#default_config_struct).await;
#test_fn(#test_fn_args).await;
test_env.core_handle.shutdown().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
}

View file

@ -53,6 +53,7 @@ escargot = "0.5.13"
# used for webdriver testing
fantoccini = { version = "0.21.4" }
futures = { workspace = true }
ldap3_client = { workspace = true }
oauth2_ext = { workspace = true, default-features = false, features = [
"reqwest",
] }

View file

@ -10,16 +10,16 @@
#![deny(clippy::needless_pass_by_value)]
#![deny(clippy::trivially_copy_pass_by_ref)]
use std::net::TcpStream;
use std::sync::atomic::{AtomicU16, Ordering};
use kanidm_client::{KanidmClient, KanidmClientBuilder};
use kanidm_proto::internal::{Filter, Modify, ModifyList};
use kanidmd_core::config::{Configuration, IntegrationTestConfig};
use kanidmd_core::{create_server_core, CoreHandle};
use kanidmd_lib::prelude::{Attribute, NAME_SYSTEM_ADMINS};
use std::net::TcpStream;
use std::sync::atomic::{AtomicU16, Ordering};
use tokio::task;
use tracing::error;
use url::Url;
pub const ADMIN_TEST_USER: &str = "admin";
pub const ADMIN_TEST_PASSWORD: &str = "integration test admin password";
@ -46,14 +46,9 @@ pub fn is_free_port(port: u16) -> bool {
}
// Test external behaviours of the service.
// allowed because the use of this function is behind a test gate
#[allow(dead_code)]
pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreHandle) {
sketching::test_init();
fn port_loop() -> u16 {
let mut counter = 0;
let port = loop {
loop {
let possible_port = PORT_ALLOC.fetch_add(1, Ordering::SeqCst);
if is_free_port(possible_port) {
break possible_port;
@ -64,7 +59,21 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH
tracing::error!("Unable to allocate port!");
panic!();
}
};
}
}
pub struct AsyncTestEnvironment {
pub rsclient: KanidmClient,
pub core_handle: CoreHandle,
pub ldap_url: Option<Url>,
}
// allowed because the use of this function is behind a test gate
#[allow(dead_code)]
pub async fn setup_async_test(mut config: Configuration) -> AsyncTestEnvironment {
sketching::test_init();
let port = port_loop();
let int_config = Box::new(IntegrationTestConfig {
admin_user: ADMIN_TEST_USER.to_string(),
@ -75,6 +84,16 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH
let addr = format!("http://localhost:{}", port);
let ldap_url = if config.ldapaddress.is_some() {
let ldapport = port_loop();
config.ldapaddress = Some(format!("127.0.0.1:{}", ldapport));
Url::parse(&format!("ldap://127.0.0.1:{}", ldapport))
.inspect_err(|err| error!(?err, "ldap address setup"))
.ok()
} else {
None
};
// Setup the address and origin..
config.address = format!("127.0.0.1:{}", port);
config.integration_test_config = Some(int_config);
@ -102,7 +121,11 @@ pub async fn setup_async_test(mut config: Configuration) -> (KanidmClient, CoreH
tracing::info!("Testkit server setup complete - {}", addr);
(rsclient, core_handle)
AsyncTestEnvironment {
rsclient,
core_handle,
ldap_url,
}
}
/// creates a user (username: `id`) and puts them into a group, creating it if need be.

View file

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use tracing::info;
#[kanidmd_testkit::test]
async fn check_that_the_swagger_api_loads(rsclient: kanidm_client::KanidmClient) {
async fn check_that_the_swagger_api_loads(rsclient: &kanidm_client::KanidmClient) {
#[derive(Serialize, Deserialize, Debug)]
struct OpenAPIResponse {
pub openapi: String,

View file

@ -3,7 +3,7 @@ use kanidm_proto::constants::ATTR_DOMAIN_DISPLAY_NAME;
use kanidmd_testkit::{ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
#[kanidmd_testkit::test]
async fn test_idm_set_ldap_allow_unix_password_bind(rsclient: KanidmClient) {
async fn test_idm_set_ldap_allow_unix_password_bind(rsclient: &KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -13,8 +13,9 @@ async fn test_idm_set_ldap_allow_unix_password_bind(rsclient: KanidmClient) {
.await
.expect("Failed to set LDAP allow unix password bind to true");
}
#[kanidmd_testkit::test]
async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
async fn test_idm_domain_set_ldap_basedn(rsclient: &KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -27,7 +28,7 @@ async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: &KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await
@ -40,7 +41,7 @@ async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_idm_domain_set_display_name(rsclient: KanidmClient) {
async fn test_idm_domain_set_display_name(rsclient: &KanidmClient) {
rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await

View file

@ -4,7 +4,7 @@ use kanidmd_testkit::{create_user, ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
use serde_json::Value;
#[kanidmd_testkit::test]
async fn test_v1_group_id_patch(rsclient: KanidmClient) {
async fn test_v1_group_id_patch(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;
@ -25,7 +25,7 @@ async fn test_v1_group_id_patch(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_v1_group_id_attr_post(rsclient: KanidmClient) {
async fn test_v1_group_id_attr_post(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;

View file

@ -1,7 +1,7 @@
use kanidm_client::{http::header, KanidmClient};
#[kanidmd_testkit::test]
async fn test_https_manifest(rsclient: KanidmClient) {
async fn test_https_manifest(rsclient: &KanidmClient) {
// We need to do manual reqwests here.
let client = rsclient.client();

View file

@ -11,7 +11,7 @@ const DEFAULT_IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
// *test where we don't trust the x-forwarded-for header
#[kanidmd_testkit::test(trust_x_forward_for = false)]
async fn dont_trust_xff_send_header(rsclient: KanidmClient) {
async fn dont_trust_xff_send_header(rsclient: &KanidmClient) {
let client = rsclient.client();
let res = client
@ -32,7 +32,7 @@ async fn dont_trust_xff_send_header(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test(trust_x_forward_for = false)]
async fn dont_trust_xff_dont_send_header(rsclient: KanidmClient) {
async fn dont_trust_xff_dont_send_header(rsclient: &KanidmClient) {
let client = rsclient.client();
let res = client
@ -58,7 +58,7 @@ async fn dont_trust_xff_dont_send_header(rsclient: KanidmClient) {
// *test where we trust the x-forwarded-for header
#[kanidmd_testkit::test(trust_x_forward_for = true)]
async fn trust_xff_send_invalid_header_single_value(rsclient: KanidmClient) {
async fn trust_xff_send_invalid_header_single_value(rsclient: &KanidmClient) {
let client = rsclient.client();
let res = client
@ -78,7 +78,7 @@ async fn trust_xff_send_invalid_header_single_value(rsclient: KanidmClient) {
// with a valid leftmost address and an invalid address later in the list. Right now it wouldn't work.
//
#[kanidmd_testkit::test(trust_x_forward_for = true)]
async fn trust_xff_send_invalid_header_multiple_values(rsclient: KanidmClient) {
async fn trust_xff_send_invalid_header_multiple_values(rsclient: &KanidmClient) {
let client = rsclient.client();
let res = client
@ -95,7 +95,7 @@ async fn trust_xff_send_invalid_header_multiple_values(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: KanidmClient) {
async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: &KanidmClient) {
let ip_addr = "2001:db8:85a3:8d3:1319:8a2e:370:7348";
let client = rsclient.client();
@ -115,7 +115,7 @@ async fn trust_xff_send_valid_header_single_ipv4_address(rsclient: KanidmClient)
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: KanidmClient) {
async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: &KanidmClient) {
let ip_addr = "203.0.113.195";
let client = rsclient.client();
@ -135,7 +135,7 @@ async fn trust_xff_send_valid_header_single_ipv6_address(rsclient: KanidmClient)
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
async fn trust_xff_send_valid_header_multiple_address(rsclient: KanidmClient) {
async fn trust_xff_send_valid_header_multiple_address(rsclient: &KanidmClient) {
let first_ip_addr = "203.0.113.195, 2001:db8:85a3:8d3:1319:8a2e:370:7348";
let client = rsclient.client();
@ -176,7 +176,7 @@ async fn trust_xff_send_valid_header_multiple_address(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test(trust_x_forward_for = true)]
async fn trust_xff_dont_send_header(rsclient: KanidmClient) {
async fn trust_xff_dont_send_header(rsclient: &KanidmClient) {
let client = rsclient.client();
let res = client

View file

@ -2,7 +2,7 @@ use kanidm_client::http::header;
use kanidm_client::KanidmClient;
#[kanidmd_testkit::test]
async fn test_https_middleware_headers(rsclient: KanidmClient) {
async fn test_https_middleware_headers(rsclient: &KanidmClient) {
// We need to do manual reqwests here.
let client = rsclient.client();

View file

@ -15,7 +15,7 @@ static USER_B_NAME: &str = "valid_user_b";
// These tests check that invalid requests return the expected error
#[kanidmd_testkit::test]
async fn test_not_authenticated(rsclient: KanidmClient) {
async fn test_not_authenticated(rsclient: &KanidmClient) {
// basically here we try a bit of all the possible combinations while unauthenticated to check it's not working
setup_server(&rsclient).await;
create_user(&rsclient, USER_A_NAME).await;
@ -46,7 +46,7 @@ async fn test_not_authenticated(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_non_existing_user_id(rsclient: KanidmClient) {
async fn test_non_existing_user_id(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
create_user(&rsclient, USER_A_NAME).await;
create_user(&rsclient, USER_B_NAME).await;
@ -86,7 +86,7 @@ async fn test_non_existing_user_id(rsclient: KanidmClient) {
// error cases have already been tested in the previous section!
// Each tests is named like `test_{api input}_response_{expected api output}_or_{expected api output}`
#[kanidmd_testkit::test]
async fn test_start_response_identity_verification_available(rsclient: KanidmClient) {
async fn test_start_response_identity_verification_available(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
create_user(&rsclient, USER_A_NAME).await;
login_with_user(&rsclient, USER_A_NAME).await;
@ -105,7 +105,7 @@ async fn test_start_response_identity_verification_available(rsclient: KanidmCli
// this function tests both possible POSITIVE outcomes if we start from
// `Start`, that is WaitForCode or ProvideCode
#[kanidmd_testkit::test]
async fn test_start_response_wait_for_code_or_provide_code(rsclient: KanidmClient) {
async fn test_start_response_wait_for_code_or_provide_code(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
@ -129,7 +129,7 @@ async fn test_start_response_wait_for_code_or_provide_code(rsclient: KanidmClien
}
#[kanidmd_testkit::test]
async fn test_provide_code_response_code_failure_or_provide_code(rsclient: KanidmClient) {
async fn test_provide_code_response_code_failure_or_provide_code(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
@ -157,7 +157,7 @@ async fn test_provide_code_response_code_failure_or_provide_code(rsclient: Kanid
// here we actually test the full idm flow by duplicating the server
#[kanidmd_testkit::test]
async fn test_full_identification_flow(rsclient: KanidmClient) {
async fn test_full_identification_flow(rsclient: &KanidmClient) {
setup_server(&rsclient).await;
let user_a_uuid = create_user(&rsclient, USER_A_NAME).await;
let user_b_uuid = create_user(&rsclient, USER_B_NAME).await;
@ -175,12 +175,12 @@ async fn test_full_identification_flow(rsclient: KanidmClient) {
(
valid_user_a_client,
USER_A_NAME,
valid_user_b_client,
&valid_user_b_client,
USER_B_NAME,
)
} else {
(
valid_user_b_client,
&valid_user_b_client,
USER_B_NAME,
valid_user_a_client,
USER_A_NAME,

View file

@ -66,7 +66,7 @@ async fn get_webdriver_client() -> fantoccini::Client {
#[kanidmd_testkit::test]
#[cfg(feature = "webdriver")]
async fn test_webdriver_user_login(rsclient: kanidm_client::KanidmClient) {
async fn test_webdriver_user_login(rsclient: &KanidmClient) {
if !cfg!(feature = "webdriver") {
println!("Skipping test as webdriver feature is not enabled!");
return;
@ -206,7 +206,7 @@ async fn test_webdriver_user_login(rsclient: kanidm_client::KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_domain_reset_token_key(rsclient: KanidmClient) {
async fn test_domain_reset_token_key(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
let token = rsclient.get_token().await.expect("No bearer token present");
@ -219,7 +219,7 @@ async fn test_domain_reset_token_key(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
async fn test_idm_domain_set_ldap_basedn(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
assert!(rsclient
.idm_domain_set_ldap_basedn("dc=krabsarekool,dc=example,dc=com")
@ -232,7 +232,7 @@ async fn test_idm_domain_set_ldap_basedn(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
assert!(rsclient
.idm_domain_set_ldap_max_queryable_attrs(20)
@ -246,7 +246,7 @@ async fn test_idm_domain_set_ldap_max_queryable_attrs(rsclient: KanidmClient) {
#[kanidmd_testkit::test]
/// Checks that a built-in group idm_all_persons has the "builtin" class as expected.
async fn test_all_persons_has_builtin_class(rsclient: KanidmClient) {
async fn test_all_persons_has_builtin_class(rsclient: &KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
let res = rsclient
.idm_group_get("idm_all_persons")

View file

@ -0,0 +1,16 @@
use kanidmd_testkit::AsyncTestEnvironment;
use ldap3_client::LdapClientBuilder;
#[kanidmd_testkit::test(ldap = true)]
async fn test_ldap_basic_unix_bind(test_env: &AsyncTestEnvironment) {
let ldap_url = test_env.ldap_url.as_ref().unwrap();
let mut ldap_client = LdapClientBuilder::new(ldap_url).build().await.unwrap();
// Bind as anonymous
ldap_client.bind("".into(), "".into()).await.unwrap();
let whoami = ldap_client.whoami().await.unwrap();
assert_eq!(whoami, Some("u: anonymous@localhost".to_string()));
}

View file

@ -6,6 +6,7 @@ mod https_extractors;
mod https_middleware;
mod identity_verification_tests;
mod integration;
mod ldap_basic;
mod mtls_test;
mod oauth2_test;
mod person;

View file

@ -40,7 +40,7 @@ use kanidmd_testkit::{
/// If `true`, use the `code` passed in the callback URI's fragment, and
/// require the query parameter to be empty.
async fn test_oauth2_openid_basic_flow_impl(
rsclient: KanidmClient,
rsclient: &KanidmClient,
response_mode: Option<&str>,
response_in_fragment: bool,
) {
@ -535,7 +535,7 @@ async fn test_oauth2_openid_basic_flow_impl(
///
/// The response should be returned as a query parameter.
#[kanidmd_testkit::test]
async fn test_oauth2_openid_basic_flow_mode_unset(rsclient: KanidmClient) {
async fn test_oauth2_openid_basic_flow_mode_unset(rsclient: &KanidmClient) {
test_oauth2_openid_basic_flow_impl(rsclient, None, false).await;
}
@ -544,7 +544,7 @@ async fn test_oauth2_openid_basic_flow_mode_unset(rsclient: KanidmClient) {
///
/// The response should be returned as a query parameter.
#[kanidmd_testkit::test]
async fn test_oauth2_openid_basic_flow_mode_query(rsclient: KanidmClient) {
async fn test_oauth2_openid_basic_flow_mode_query(rsclient: &KanidmClient) {
test_oauth2_openid_basic_flow_impl(rsclient, Some("query"), false).await;
}
@ -553,7 +553,7 @@ async fn test_oauth2_openid_basic_flow_mode_query(rsclient: KanidmClient) {
///
/// The response should be returned in the URI's fragment.
#[kanidmd_testkit::test]
async fn test_oauth2_openid_basic_flow_mode_fragment(rsclient: KanidmClient) {
async fn test_oauth2_openid_basic_flow_mode_fragment(rsclient: &KanidmClient) {
test_oauth2_openid_basic_flow_impl(rsclient, Some("fragment"), true).await;
}
@ -570,7 +570,7 @@ async fn test_oauth2_openid_basic_flow_mode_fragment(rsclient: KanidmClient) {
/// If `true`, use the `code` passed in the callback URI's fragment, and
/// require the query parameter to be empty.
async fn test_oauth2_openid_public_flow_impl(
rsclient: KanidmClient,
rsclient: &KanidmClient,
response_mode: Option<&str>,
response_in_fragment: bool,
) {
@ -901,7 +901,7 @@ async fn test_oauth2_openid_public_flow_impl(
///
/// The response should be returned as a query parameter.
#[kanidmd_testkit::test]
async fn test_oauth2_openid_public_flow_mode_unset(rsclient: KanidmClient) {
async fn test_oauth2_openid_public_flow_mode_unset(rsclient: &KanidmClient) {
test_oauth2_openid_public_flow_impl(rsclient, None, false).await;
}
@ -910,7 +910,7 @@ async fn test_oauth2_openid_public_flow_mode_unset(rsclient: KanidmClient) {
///
/// The response should be returned as a query parameter.
#[kanidmd_testkit::test]
async fn test_oauth2_openid_public_flow_mode_query(rsclient: KanidmClient) {
async fn test_oauth2_openid_public_flow_mode_query(rsclient: &KanidmClient) {
test_oauth2_openid_public_flow_impl(rsclient, Some("query"), false).await;
}
@ -919,12 +919,12 @@ async fn test_oauth2_openid_public_flow_mode_query(rsclient: KanidmClient) {
///
/// The response should be returned in the URI's fragment.
#[kanidmd_testkit::test]
async fn test_oauth2_openid_public_flow_mode_fragment(rsclient: KanidmClient) {
async fn test_oauth2_openid_public_flow_mode_fragment(rsclient: &KanidmClient) {
test_oauth2_openid_public_flow_impl(rsclient, Some("fragment"), true).await;
}
#[kanidmd_testkit::test]
async fn test_oauth2_token_post_bad_bodies(rsclient: KanidmClient) {
async fn test_oauth2_token_post_bad_bodies(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;
@ -960,7 +960,7 @@ async fn test_oauth2_token_post_bad_bodies(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_oauth2_token_revoke_post(rsclient: KanidmClient) {
async fn test_oauth2_token_revoke_post(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;

View file

@ -4,7 +4,7 @@ use kanidmd_testkit::{create_user, ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
use serde_json::Value;
#[kanidmd_testkit::test]
async fn test_v1_person_id_patch(rsclient: KanidmClient) {
async fn test_v1_person_id_patch(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;
@ -25,7 +25,7 @@ async fn test_v1_person_id_patch(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_v1_person_id_ssh_pubkeys_post(rsclient: KanidmClient) {
async fn test_v1_person_id_ssh_pubkeys_post(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;

View file

@ -29,7 +29,7 @@ use kanidmd_testkit::{ADMIN_TEST_PASSWORD, ADMIN_TEST_USER};
const UNIX_TEST_PASSWORD: &str = "unix test user password";
#[kanidmd_testkit::test]
async fn test_server_create(rsclient: KanidmClient) {
async fn test_server_create(rsclient: &KanidmClient) {
let e: Entry = serde_json::from_str(
r#"{
"attrs": {
@ -55,7 +55,7 @@ async fn test_server_create(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_whoami_anonymous(rsclient: KanidmClient) {
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.
@ -84,7 +84,7 @@ async fn test_server_whoami_anonymous(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_whoami_admin_simple_password(rsclient: KanidmClient) {
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.
@ -109,7 +109,7 @@ async fn test_server_whoami_admin_simple_password(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_search(rsclient: KanidmClient) {
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.
@ -135,7 +135,7 @@ async fn test_server_search(rsclient: KanidmClient) {
// test the rest group endpoint.
#[kanidmd_testkit::test]
async fn test_server_rest_group_read(rsclient: KanidmClient) {
async fn test_server_rest_group_read(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -151,7 +151,7 @@ async fn test_server_rest_group_read(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_group_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -263,7 +263,7 @@ async fn test_server_rest_group_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_account_read(rsclient: KanidmClient) {
async fn test_server_rest_account_read(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -279,7 +279,7 @@ async fn test_server_rest_account_read(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_schema_read(rsclient: KanidmClient) {
async fn test_server_rest_schema_read(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -313,7 +313,7 @@ async fn test_server_rest_schema_read(rsclient: KanidmClient) {
// Test resetting a radius cred, and then checking/viewing it.
#[kanidmd_testkit::test]
async fn test_server_radius_credential_lifecycle(rsclient: KanidmClient) {
async fn test_server_radius_credential_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -384,7 +384,7 @@ async fn test_server_radius_credential_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_person_account_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_person_account_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -439,7 +439,7 @@ async fn test_server_rest_person_account_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_sshkey_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_sshkey_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -509,7 +509,7 @@ async fn test_server_rest_sshkey_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_domain_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_domain_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -539,7 +539,7 @@ async fn test_server_rest_domain_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_posix_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_posix_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -660,7 +660,7 @@ async fn test_server_rest_posix_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_posix_auth_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_posix_auth_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -760,7 +760,7 @@ async fn test_server_rest_posix_auth_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_recycle_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_recycle_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -814,7 +814,7 @@ async fn test_server_rest_recycle_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
async fn test_server_rest_oauth2_basic_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -1027,7 +1027,7 @@ async fn test_server_rest_oauth2_basic_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_pw(rsclient: KanidmClient) {
async fn test_server_credential_update_session_pw(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -1102,7 +1102,7 @@ async fn test_server_credential_update_session_pw(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_totp_pw(rsclient: KanidmClient) {
async fn test_server_credential_update_session_totp_pw(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;
@ -1365,7 +1365,7 @@ async fn setup_demo_account_password(
}
#[kanidmd_testkit::test]
async fn test_server_credential_update_session_passkey(rsclient: KanidmClient) {
async fn test_server_credential_update_session_passkey(rsclient: &KanidmClient) {
let mut wa = setup_demo_account_passkey(&rsclient).await;
let res = rsclient
@ -1383,7 +1383,7 @@ async fn test_server_credential_update_session_passkey(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
async fn test_server_api_token_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;
@ -1566,7 +1566,7 @@ async fn test_server_api_token_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
async fn test_server_user_auth_token_lifecycle(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;
@ -1689,7 +1689,7 @@ async fn test_server_user_auth_token_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_user_auth_reauthentication(rsclient: KanidmClient) {
async fn test_server_user_auth_reauthentication(rsclient: &KanidmClient) {
let mut wa = setup_demo_account_passkey(&rsclient).await;
let res = rsclient
@ -1868,7 +1868,7 @@ async fn start_password_session(
}
#[kanidmd_testkit::test]
async fn test_server_user_auth_unprivileged(rsclient: KanidmClient) {
async fn test_server_user_auth_unprivileged(rsclient: &KanidmClient) {
let (account_name, account_pass) = setup_demo_account_password(&rsclient)
.await
.expect("Failed to setup demo_account");
@ -1891,7 +1891,7 @@ async fn test_server_user_auth_unprivileged(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_server_user_auth_privileged_shortcut(rsclient: KanidmClient) {
async fn test_server_user_auth_privileged_shortcut(rsclient: &KanidmClient) {
let (account_name, account_pass) = setup_demo_account_password(&rsclient)
.await
.expect("Failed to setup demo_account");

View file

@ -9,7 +9,7 @@ use std::str::FromStr;
use url::Url;
#[kanidmd_testkit::test]
async fn test_sync_account_lifecycle(rsclient: KanidmClient) {
async fn test_sync_account_lifecycle(rsclient: &KanidmClient) {
let a_res = rsclient
.auth_simple_password(ADMIN_TEST_USER, ADMIN_TEST_PASSWORD)
.await;
@ -104,7 +104,7 @@ async fn test_sync_account_lifecycle(rsclient: KanidmClient) {
}
#[kanidmd_testkit::test]
async fn test_scim_sync_entry_get(rsclient: KanidmClient) {
async fn test_scim_sync_entry_get(rsclient: &KanidmClient) {
let res = rsclient
.auth_simple_password("admin", ADMIN_TEST_PASSWORD)
.await;

View file

@ -2,7 +2,7 @@ use kanidm_client::KanidmClient;
/// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
#[kanidmd_testkit::test]
async fn test_v1_service_account_id_attr_attr_delete(rsclient: KanidmClient) {
async fn test_v1_service_account_id_attr_attr_delete(rsclient: &KanidmClient) {
// We need to do manual reqwests here.
let client = rsclient.client();

View file

@ -2,7 +2,7 @@ use kanidm_client::KanidmClient;
/// This literally tests that the thing exists and responds in a way we expect, probably worth testing it better...
#[kanidmd_testkit::test]
async fn test_v1_system_post_attr(rsclient: KanidmClient) {
async fn test_v1_system_post_attr(rsclient: &KanidmClient) {
let client = rsclient.client();
let response = match client

View file

@ -3,8 +3,8 @@ use kanidmd_lib::constants::NAME_IDM_ADMINS;
use kanidmd_testkit::*;
#[kanidmd_testkit::test]
async fn account_id_unix_token(rsclient: KanidmClient) {
login_put_admin_idm_admins(&rsclient).await;
async fn account_id_unix_token(rsclient: &KanidmClient) {
login_put_admin_idm_admins(rsclient).await;
create_user(&rsclient, "group_manager", "idm_group_manage_priv").await;
// create test user without creating new groups