diff --git a/src/api.rs b/src/api.rs index 5afb938c..f8d3df90 100644 --- a/src/api.rs +++ b/src/api.rs @@ -30,7 +30,7 @@ use self::sys::responses::WrappingLookupResponse; /// are automatically logged accordingly. #[derive(Deserialize, Debug)] pub struct EndpointResult { - pub data: Option, + pub data: Option>, pub auth: Option, pub lease_id: String, pub lease_duration: u32, @@ -40,6 +40,14 @@ pub struct EndpointResult { pub wrap_info: Option, } +/// Fixes deserializing empty "data" if it is returned by API as empty object +#[derive(Deserialize, Debug)] +#[serde(untagged)] +pub enum EitherData { + Real(T), + Empty {}, +} + impl rustify::endpoint::Wrapper for EndpointResult { type Value = T; } @@ -365,7 +373,11 @@ where true => {} } } - result.data + match result.data { + None => None, + Some(EitherData::Empty {}) => None, + Some(EitherData::Real(data)) => Some(data), + } } /// Attempts to parse the enclosed API errors returned from a diff --git a/src/api/auth.rs b/src/api/auth.rs index 931ba355..3887b199 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -1,5 +1,6 @@ pub mod approle; pub mod aws; pub mod kubernetes; +pub mod ldap; pub mod oidc; pub mod userpass; diff --git a/src/api/auth/ldap.rs b/src/api/auth/ldap.rs new file mode 100644 index 00000000..116da0fe --- /dev/null +++ b/src/api/auth/ldap.rs @@ -0,0 +1,2 @@ +pub mod requests; +pub mod responses; diff --git a/src/api/auth/ldap/requests.rs b/src/api/auth/ldap/requests.rs new file mode 100644 index 00000000..fdfc023b --- /dev/null +++ b/src/api/auth/ldap/requests.rs @@ -0,0 +1,242 @@ +use super::responses::{ + ListLDAPGroupsResponse, ListLDAPUsersResponse, ReadLDAPGroupResponse, ReadLDAPUserResponse, +}; +use rustify_derive::Endpoint; + +/// ## Configure Client +/// Configures LDAP endpoint. +/// +/// * Path: /auth/{self.mount}/config +/// * Method: POST +/// * Response: N/A +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#configure-ldap +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint(path = "/auth/{self.mount}/config", method = "POST", builder = "true")] +#[builder(setter(into, strip_option), default)] +pub struct ConfigureClientRequest { + #[endpoint(skip)] + pub mount: String, + pub url: Option, + pub case_sensitive_names: Option, + pub request_timeout: Option, + pub starttls: Option, + pub tls_min_version: Option, + pub tls_max_version: Option, + pub insecure_tls: Option, + pub certificate: Option, + pub client_tls_cert: Option, + pub client_tls_key: Option, + pub binddn: Option, + pub bindpass: Option, + pub userdn: Option, + pub userattr: Option, + pub discoverdn: Option, + pub deny_null_bind: Option, + pub upndomain: Option, + pub userfilter: Option, + pub anonymous_group_search: Option, + pub groupfilter: Option, + pub groupdn: Option, + pub groupattr: Option, + pub username_as_alias: Option, + pub token_ttl: Option, + pub token_max_ttl: Option, + pub token_policies: Option, + pub token_bound_cidrs: Option, + pub token_explicit_max_ttl: Option, + pub token_no_default_policy: Option, + pub token_num_uses: Option, + pub token_period: Option, + pub token_type: Option, +} + +/// ## List LDAP groups +/// Returns a list of existing groups. +/// +/// * Path: /auth/{self.mount}/groups +/// * Method: LIST +/// * Response: [ListLDAPGroupsResponse] +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#list-ldap-groups +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/groups", + method = "LIST", + response = "ListLDAPGroupsResponse", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct ListLDAPGroupsRequest { + #[endpoint(skip)] + pub mount: String, +} + +/// ## Read LDAP Group +/// Reads the policies associated with a LDAP group. +/// +/// * Path: /auth/{self.mount}/groups/{self.groupname} +/// * Method: GET +/// * Response: [ReadLDAPGroupResponse] +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#read-ldap-group +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/groups/{self.groupname}", + response = "ReadLDAPGroupResponse", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct ReadLDAPGroupRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub groupname: String, +} + +/// ## Create/Update LDAP Group +/// Creates or updates LDAP group policies. +/// +/// * Path: /auth/{self.mount}/users/{self.groupname} +/// * Method: POST +/// * Response: N/A +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#create-update-ldap-group +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/groups/{self.groupname}", + method = "POST", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct CreateLDAPGroupRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub groupname: String, + pub policies: String, +} + +/// ## Delete LDAP Group +/// Deletes the LDAP group and policy association. +/// +/// * Path: /auth/{self.mount}/groups/{self.groupname} +/// * Method: DELETE +/// * Response: N/A +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#delete-ldap-group +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/groups/{self.groupname}", + method = "DELETE", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct DeleteLDAPGroupRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub groupname: String, +} + +/// ## Create/Update LDAP User +/// This endpoint creates or updates LDAP users policies and group associations. +/// +/// * Path: /auth/{self.mount}/users/{self.username} +/// * Method: POST +/// * Response: N/A +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#create-update-ldap-user +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/users/{self.username}", + method = "POST", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct CreateLDAPUserRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub username: String, + pub policies: String, + pub groups: String, +} + +/// ## Read LDAP User +/// Reads the properties of an existing username. +/// +/// * Path: /auth/{self.mount}/users/{self.username} +/// * Method: GET +/// * Response: [ReadUserResponse] +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#read-ldap-user +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/users/{self.username}", + response = "ReadLDAPUserResponse", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct ReadLDAPUserRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub username: String, +} + +/// ## List Users +/// List available LDAP users. +/// +/// * Path: /auth/{self.mount}/users +/// * Method: LIST +/// * Response: [ListLDAPUsersResponse] +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#list-ldap-users +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/users", + method = "LIST", + response = "ListLDAPUsersResponse", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct ListLDAPUsersRequest { + #[endpoint(skip)] + pub mount: String, +} + +/// ## Delete User +/// This endpoint deletes the LDAP user and policy association. +/// +/// * Path: /auth/{self.mount}/users/{self.username} +/// * Method: DELETE +/// * Response: N/A +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#delete-ldap-user +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/users/{self.username}", + method = "DELETE", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct DeleteLDAPUserRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub username: String, +} + +/// ## Login +/// Login with the username and password. +/// +/// * Path: /auth/{self.mount}/login/{self.username} +/// * Method: POST +/// * Response: N/A +/// * Reference: https://www.vaultproject.io/api-docs/auth/ldap#login-with-ldap-user +#[derive(Builder, Debug, Default, Endpoint)] +#[endpoint( + path = "/auth/{self.mount}/login/{self.username}", + method = "POST", + builder = "true" +)] +#[builder(setter(into, strip_option), default)] +pub struct LoginRequest { + #[endpoint(skip)] + pub mount: String, + #[endpoint(skip)] + pub username: String, + pub password: String, +} diff --git a/src/api/auth/ldap/responses.rs b/src/api/auth/ldap/responses.rs new file mode 100644 index 00000000..9eca2ed3 --- /dev/null +++ b/src/api/auth/ldap/responses.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +/// Response from executing +/// [ListLDAPGroupsRequest][crate::api::auth::ldap::requests::ListLDAPGroupsRequest] +#[derive(Deserialize, Debug, Serialize)] +pub struct ListLDAPGroupsResponse { + pub keys: Vec, +} + +/// Response from executing +/// [ReadLDAPGroupRequest][crate::api::auth::ldap::requests::ReadLDAPGroupRequest] +#[derive(Deserialize, Debug, Serialize)] +pub struct ReadLDAPGroupResponse { + pub policies: Vec, +} + +/// Response from executing +/// [ListLDAPUsersRequest][crate::api::auth::ldap::requests::ListLDAPUsersRequest] +#[derive(Deserialize, Debug, Serialize)] +pub struct ListLDAPUsersResponse { + pub keys: Vec, +} + +/// Response from executing +/// [ReadLDAPUserRequest][crate::api::auth::ldap::requests::ReadLDAPUserRequest] +#[derive(Deserialize, Debug, Serialize)] +pub struct ReadLDAPUserResponse { + pub policies: Vec, + pub groups: String, +} diff --git a/src/auth.rs b/src/auth.rs index 931ba355..3887b199 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,5 +1,6 @@ pub mod approle; pub mod aws; pub mod kubernetes; +pub mod ldap; pub mod oidc; pub mod userpass; diff --git a/src/auth/ldap.rs b/src/auth/ldap.rs new file mode 100644 index 00000000..28bfdc7c --- /dev/null +++ b/src/auth/ldap.rs @@ -0,0 +1,240 @@ +use crate::{ + api::{self, auth::ldap::requests::LoginRequest, AuthInfo}, + client::Client, + error::ClientError, +}; + +// Fetch a token with policies corresponding to the username. +// +// See [LoginRequest] +#[instrument(skip(client, password), err)] +pub async fn login( + client: &impl Client, + mount: &str, + username: &str, + password: &str, +) -> Result { + let endpoint = LoginRequest::builder() + .mount(mount) + .username(username) + .password(password) + .build() + .unwrap(); + api::auth(client, endpoint).await +} + +pub mod user { + use crate::{ + api::{ + self, + auth::ldap::{ + requests::{ + CreateLDAPUserRequest, CreateLDAPUserRequestBuilder, DeleteLDAPUserRequest, + ListLDAPUsersRequest, ReadLDAPUserRequest, + }, + responses::{ListLDAPUsersResponse, ReadLDAPUserResponse}, + }, + }, + client::Client, + error::ClientError, + }; + + /// Deletes a user. + /// + /// See [DeleteLDAPUserRequest] + #[instrument(skip(client), err)] + pub async fn delete( + client: &impl Client, + mount: &str, + username: &str, + ) -> Result<(), ClientError> { + let endpoint = DeleteLDAPUserRequest::builder() + .mount(mount) + .username(username) + .build() + .unwrap(); + api::exec_with_empty(client, endpoint).await + } + + /// Lists users. + /// + /// See [ListLDAPUsersRequest] + #[instrument(skip(client), err)] + pub async fn list( + client: &impl Client, + mount: &str, + ) -> Result { + let endpoint = ListLDAPUsersRequest::builder() + .mount(mount) + .build() + .unwrap(); + api::exec_with_result(client, endpoint).await + } + + /// Reads information about a user. + /// + /// See [ReadLDAPUserRequest] + #[instrument(skip(client), err)] + pub async fn read( + client: &impl Client, + mount: &str, + username: &str, + ) -> Result { + let endpoint = ReadLDAPUserRequest::builder() + .mount(mount) + .username(username) + .build() + .unwrap(); + api::exec_with_result(client, endpoint).await + } + + /// Crates or updates a new user. + /// + /// See [CreateLDAPUserRequest] + #[instrument(skip(client, opts), err)] + pub async fn set( + client: &impl Client, + mount: &str, + username: &str, + policies: &str, + groups: &str, + opts: Option<&mut CreateLDAPUserRequestBuilder>, + ) -> Result<(), ClientError> { + let mut t = CreateLDAPUserRequest::builder(); + let endpoint = opts + .unwrap_or(&mut t) + .mount(mount) + .username(username) + .policies(policies) + .groups(groups) + .build() + .unwrap(); + api::exec_with_empty(client, endpoint).await + } + + /// Updates a user's groups. + /// + /// See [CreateLDAPUserRequest] + #[instrument(skip(client), err)] + pub async fn update_groups( + client: &impl Client, + mount: &str, + username: &str, + groups: &str, + ) -> Result<(), ClientError> { + let endpoint = CreateLDAPUserRequest::builder() + .mount(mount) + .username(username) + .groups(groups) + .build() + .unwrap(); + api::exec_with_empty(client, endpoint).await + } + + /// Updates a user's policies. + /// + /// See [CreateLDAPUserRequest] + #[instrument(skip(client), err)] + pub async fn update_policies( + client: &impl Client, + mount: &str, + username: &str, + policies: &str, + ) -> Result<(), ClientError> { + let endpoint = CreateLDAPUserRequest::builder() + .mount(mount) + .username(username) + .policies(policies) + .build() + .unwrap(); + api::exec_with_empty(client, endpoint).await + } +} + +pub mod group { + use crate::{ + api::{ + self, + auth::ldap::{ + requests::{ + CreateLDAPGroupRequest, CreateLDAPGroupRequestBuilder, DeleteLDAPGroupRequest, + ListLDAPGroupsRequest, ReadLDAPGroupRequest, + }, + responses::{ListLDAPGroupsResponse, ReadLDAPGroupResponse}, + }, + }, + client::Client, + error::ClientError, + }; + + /// Deletes a user. + /// + /// See [DeleteLDAPGroupRequest] + #[instrument(skip(client), err)] + pub async fn delete( + client: &impl Client, + mount: &str, + groupname: &str, + ) -> Result<(), ClientError> { + let endpoint = DeleteLDAPGroupRequest::builder() + .mount(mount) + .groupname(groupname) + .build() + .unwrap(); + api::exec_with_empty(client, endpoint).await + } + + /// Lists users. + /// + /// See [ListLDAPGroupsRequest] + #[instrument(skip(client), err)] + pub async fn list( + client: &impl Client, + mount: &str, + ) -> Result { + let endpoint = ListLDAPGroupsRequest::builder() + .mount(mount) + .build() + .unwrap(); + api::exec_with_result(client, endpoint).await + } + + /// Reads information about a user. + /// + /// See [ReadGroupRequest] + #[instrument(skip(client), err)] + pub async fn read( + client: &impl Client, + mount: &str, + groupname: &str, + ) -> Result { + let endpoint = ReadLDAPGroupRequest::builder() + .mount(mount) + .groupname(groupname) + .build() + .unwrap(); + api::exec_with_result(client, endpoint).await + } + + /// Crates or updates a new user. + /// + /// See [CreateLDAPGroupRequest] + #[instrument(skip(client, opts), err)] + pub async fn set( + client: &impl Client, + mount: &str, + groupname: &str, + policies: &str, + opts: Option<&mut CreateLDAPGroupRequestBuilder>, + ) -> Result<(), ClientError> { + let mut t = CreateLDAPGroupRequest::builder(); + let endpoint = opts + .unwrap_or(&mut t) + .mount(mount) + .groupname(groupname) + .policies(policies) + .build() + .unwrap(); + api::exec_with_empty(client, endpoint).await + } +} diff --git a/tests/common.rs b/tests/common.rs index 85852bba..ab48c534 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -177,6 +177,35 @@ pub fn new_aws_test() -> Test { test } +// Sets up a new LDAP test. +#[allow(dead_code)] +pub fn new_ldap_test() -> Test { + let mut test = new_test(); + let localstack_config = LocalStackServerConfig::builder() + .handle(String::from("bitnami/openldap")) + .port(4566) + .env( + vec![ + (String::from("LDAP_ADMIN_USERNAME"), String::from("vault")), + ( + String::from("LDAP_ADMIN_PASSWORD"), + String::from("adminpassword"), + ), + (String::from("LDAP_USERS"), String::from("test")), + (String::from("LDAP_PASSWORDS"), String::from("This1sAT3st")), + (String::from("LDAP_PORT_NUMBER"), String::from("4566")), + ] + .into_iter() + .collect::>(), + ) + .version("latest".to_string()) + .args(vec![String::from("-p"), String::from("4566:4566")]) + .build() + .unwrap(); + test.register(localstack_config); + test +} + // Sets up a new webserver test. #[allow(dead_code)] pub fn new_webserver_test() -> (Test, ManagedContent) { diff --git a/tests/ldap.rs b/tests/ldap.rs new file mode 100644 index 00000000..0694d248 --- /dev/null +++ b/tests/ldap.rs @@ -0,0 +1,253 @@ +#[macro_use] +extern crate tracing; + +mod common; + +use common::{VaultServer, VaultServerHelper}; +use dockertest_server::servers::cloud::LocalStackServer; +use test_log::test; +use vaultrs::auth::ldap; +use vaultrs::client::Client; +use vaultrs::error::ClientError; + +#[test] +fn test_all() { + let user_test = common::new_ldap_test(); + user_test.run(|instance| async move { + let localstack: LocalStackServer = instance.server(); + let server: VaultServer = instance.server(); + let client = server.client(); + let endpoint = setup(&server, &client).await.unwrap(); + + // Test configuring ldap endpoint + config::configure_endpoint(&client, &endpoint, &localstack).await; + + // Test user + user::test_set(&client, &endpoint).await; + user::test_read(&client, &endpoint).await; + user::test_list(&client, &endpoint).await; + user::test_update_policies(&client, &endpoint).await; + + // Test login + test_login(&client, &endpoint).await; + + // Test update user groups and delete + user::test_update_groups(&client, &endpoint).await; + user::test_delete(&client, &endpoint).await; + }); + + let group_test = common::new_test(); + group_test.run(|instance| async move { + let server: VaultServer = instance.server(); + let client = server.client(); + let endpoint = setup(&server, &client).await.unwrap(); + + // Test group + group::test_set(&client, &endpoint).await; + group::test_read(&client, &endpoint).await; + group::test_list(&client, &endpoint).await; + + // Test delete + user::test_delete(&client, &endpoint).await; + }); +} + +pub async fn test_login(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = ldap::login( + client, + endpoint.path.as_str(), + endpoint.username.as_str(), + endpoint.password.as_str(), + ) + .await; + println!("{:?}", &res); + // manually verified with: + // * ldap server started with: + // ```shell + // docker run --rm --name openldap -p 4566:4566 \ + // --env LDAP_LOGLEVEL=512 \ + // --env LDAP_ADMIN_USERNAME=vault \ + // --env LDAP_ADMIN_PASSWORD=adminpassword \ + // --env LDAP_USERS=test \ + // --env LDAP_PASSWORDS='This1sAT3st' \ + // --env LDAP_PORT_NUMBER=4566 \ + // bitnami/openldap:latest + // ``` + // * vault server started with: `vault server -dev -log-level=debug` + // * `vault auth enable ldap` - enable ldap auth engine + // * configure ldap auth engine: + // ```shell + // vault write auth/ldap/config \ + // url="ldap://localhost:4566" \ + // userdn="ou=users,dc=example,dc=org" \ + // groupdn="ou=users,dc=example,dc=org" \ + // userattr="cn" \ + // insecure_tls=true \ + // starttls=false \ + // groupattr="groupOfNames" \ + // bindpass="adminpassword" \ + // groupfilter="(&(objectClass=groupOfNames)(member=cn={{.Username}},{{.UserDN}}))" + // ``` + // * try manually login to vault: `vault login --method ldap username=test` - works + // * try manually login through test app (also works just fine): + // ```rust + // use std::error::Error; + // use vaultrs::client::{VaultClient, VaultClientSettingsBuilder}; + // #[tokio::main] + // async fn main() -> Result<(), Box> { + // env_logger::init(); + // let client = VaultClient::new( + // VaultClientSettingsBuilder::default() + // .address("http://127.0.0.1:8200") + // .build() + // .unwrap() + // ).unwrap(); + // println!("{:?}", vaultrs::auth::ldap::login( + // &client, "ldap", "test", "This1sAT3st").await); + // Ok(()) + // } + // ``` + // But here it doesn't work: + // TODO: fix ldap auth test + assert!(res.is_ok()); +} + +pub mod config { + use super::{Client, LDAPEndpoint}; + use dockertest_server::servers::cloud::LocalStackServer; + use vaultrs::api::auth::ldap::requests::ConfigureClientRequest; + + pub async fn configure_endpoint( + client: &impl Client, + endpoint: &LDAPEndpoint, + localstack: &LocalStackServer, + ) { + let endpoint = ConfigureClientRequest::builder() + .mount(endpoint.path.as_str()) + .url(&format!("ldap://{}", localstack.internal_address())) + .userdn("ou=users,dc=example,dc=org") + .groupdn("ou=users,dc=example,dc=org") + .userattr("cn") + .groupattr("groupOfNames") + .groupfilter("(&(objectClass=groupOfNames)(member=cn={{.Username}},{{.UserDN}}))") + .discoverdn(true) + .insecure_tls(true) + .starttls(false) + .bindpass("adminpassword") + .build() + .unwrap(); + let res = vaultrs::api::exec_with_empty(client, endpoint).await; + assert!(res.is_ok()); + } +} + +pub mod user { + use super::{Client, LDAPEndpoint}; + use vaultrs::auth::ldap::user; + + pub async fn test_delete(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = user::delete(client, endpoint.path.as_str(), endpoint.username.as_str()).await; + assert!(res.is_ok()); + } + + pub async fn test_list(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = user::list(client, endpoint.path.as_str()).await; + assert!(res.is_ok()); + } + + pub async fn test_read(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = user::read(client, endpoint.path.as_str(), endpoint.username.as_str()).await; + assert!(res.is_ok()); + } + + pub async fn test_set(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = user::set( + client, + endpoint.path.as_str(), + endpoint.username.as_str(), + "default,admin", + "dev.test,vault.admins", + None, + ) + .await; + assert!(res.is_ok()); + } + + pub async fn test_update_groups(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = user::update_groups( + client, + endpoint.path.as_str(), + endpoint.username.as_str(), + "vault.admins", + ) + .await; + assert!(res.is_ok()); + } + + pub async fn test_update_policies(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = user::update_policies( + client, + endpoint.path.as_str(), + endpoint.username.as_str(), + "default", + ) + .await; + assert!(res.is_ok()); + } +} + +pub mod group { + use super::{Client, LDAPEndpoint}; + use vaultrs::auth::ldap::group; + + pub async fn test_delete(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = group::delete(client, endpoint.path.as_str(), "vault.admins").await; + assert!(res.is_ok()); + } + + pub async fn test_list(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = group::list(client, endpoint.path.as_str()).await; + assert!(res.is_ok()); + } + + pub async fn test_read(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = group::read(client, endpoint.path.as_str(), "vault.admins").await; + assert!(res.is_ok()); + } + + pub async fn test_set(client: &impl Client, endpoint: &LDAPEndpoint) { + let res = group::set( + client, + endpoint.path.as_str(), + "vault.admins", + "default,admin", + None, + ) + .await; + assert!(res.is_ok()); + } +} + +#[derive(Debug)] +pub struct LDAPEndpoint { + pub path: String, + pub username: String, + pub password: String, +} + +async fn setup(server: &VaultServer, client: &impl Client) -> Result { + debug!("setting up LDAP auth engine"); + + let path = "ldap_test"; + let username = "test"; + let password = "This1sAT3st"; + + // Mount the LDAP auth engine + server.mount_auth(client, path, "ldap").await?; + + Ok(LDAPEndpoint { + path: path.to_string(), + username: username.to_string(), + password: password.to_string(), + }) +}