Skip to content

Commit

Permalink
feat!: Make using attribute filters optional
Browse files Browse the repository at this point in the history
  • Loading branch information
tlater-famedly committed Aug 9, 2024
1 parent c2edef5 commit 75ed0bf
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 27 deletions.
9 changes: 8 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ useless_let_if_seq = "warn"
verbose_file_reads = "warn"

[dev-dependencies]
indoc = "2.0.5"
ldap3 = { version = "0.11.1", default-features = false, features = ["tls-native"] }
tempfile = "3.10.1"
test-log = { version = "0.2.16", features = ["trace", "unstable"] }
6 changes: 6 additions & 0 deletions config.sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ ldap:
timeout: 5
# Whether to sync entry deletion.
check_for_deleted_entries: true
# Whether to filter for the specific attributes used. Some LDAP
# implementations misbehave if this is not done, others misbehave if
# it is done.
#
# Default is false.
use_attribute_filter: true
# A mapping of the LDAP attributes to Famedly attributes. This is
# different for different LDAP server implementations and
# organizations, so needs to be configured on a case-by-case basis.
Expand Down
125 changes: 99 additions & 26 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,6 @@ fn validate_famedly_url(url: Url) -> Result<Url> {
Ok(url)
}

#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
use super::*;

#[test]
fn test_famedly_url_validate_valid() {
let url = Url::parse("https://famedly.de").expect("invalid url");
let validated = validate_famedly_url(url).expect("url failed to validate");
assert_eq!(validated.to_string(), "https://famedly.de/");
}

#[test]
fn test_famedly_url_validate_trailing_slash_path() {
let url = Url::parse("https://famedly.de/test/").expect("invalid url");
let validated = validate_famedly_url(url).expect("url failed to validate");
assert_eq!(validated.to_string(), "https://famedly.de/test/");
}

#[test]
fn test_famedly_url_validate_scheme() {
let url = Url::parse("famedly.de:443").expect("invalid url");
assert!(validate_famedly_url(url).is_err());
}
}

/// Configuration for the sync client
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
Expand Down Expand Up @@ -115,6 +89,11 @@ pub struct LdapConfig {
pub attributes: LdapAttributesMapping,
/// Whether to update deleted entries
pub check_for_deleted_entries: bool,
/// Whether to ask LDAP for specific attributes or just specify *.
///
/// Various implementations either do or don't send data in both
/// cases, so this needs to be tested against the actual server.
pub use_attribute_filter: bool,
/// TLS-related configuration
pub tls: Option<LdapTlsConfig>,
}
Expand Down Expand Up @@ -156,6 +135,7 @@ impl From<LdapConfig> for ldap_poller::Config {
pid: attributes.user_id.get_name(),
updated: attributes.last_modified.map(AttributeMapping::get_name),
additional: vec![],
filter_attributes: cfg.use_attribute_filter,
attrs_to_track: vec![
attributes.status.get_name(),
attributes.first_name.get_name(),
Expand Down Expand Up @@ -291,3 +271,96 @@ pub enum FeatureFlag {
/// If users should verify the phone. Users will receive a verification sms
VerifyPhone,
}

#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use indoc::indoc;

use super::*;

const EXAMPLE_CONFIG: &str = indoc! {r#"
ldap:
url: ldap://localhost:1389
base_dn: ou=testorg,dc=example,dc=org
bind_dn: cn=admin,dc=example,dc=org
bind_password: adminpassword
user_filter: "(objectClass=shadowAccount)"
timeout: 5
check_for_deleted_entries: true
use_attribute_filter: true
attributes:
first_name: "cn"
last_name: "sn"
preferred_username: "displayName"
email: "mail"
phone: "telephoneNumber"
user_id: "uid"
status:
name: "shadowInactive"
is_binary: false
enable_value: 512
disable_value: 514
tls:
client_key: ./tests/environment/certs/client.key
client_certificate: ./tests/environment/certs/client.crt
server_certificate: ./tests/environment/certs/server.crt
danger_disable_tls_verify: false
danger_use_start_tls: false
famedly:
url: http://localhost:8080
key_file: tests/environment/zitadel/service-user.json
organization_id: 1
project_id: 1
idp_id: 1
feature_flags: []
cache_path: ./test
"#};

fn example_config() -> Config {
serde_yaml::from_str(EXAMPLE_CONFIG).expect("invalid config")
}

#[test]
fn test_famedly_url_validate_valid() {
let url = Url::parse("https://famedly.de").expect("invalid url");
let validated = validate_famedly_url(url).expect("url failed to validate");
assert_eq!(validated.to_string(), "https://famedly.de/");
}

#[test]
fn test_famedly_url_validate_trailing_slash_path() {
let url = Url::parse("https://famedly.de/test/").expect("invalid url");
let validated = validate_famedly_url(url).expect("url failed to validate");
assert_eq!(validated.to_string(), "https://famedly.de/test/");
}

#[test]
fn test_famedly_url_validate_scheme() {
let url = Url::parse("famedly.de:443").expect("invalid url");
assert!(validate_famedly_url(url).is_err());
}

#[test]
fn test_attribute_filter_use() {
let config = example_config();

assert_eq!(
Into::<ldap_poller::Config>::into(config.ldap).attributes.get_attr_filter(),
vec!["uid", "shadowInactive", "cn", "sn", "displayName", "mail", "telephoneNumber"]
);
}

#[test]
fn test_no_attribute_filters() {
let mut config = example_config();
config.ldap.use_attribute_filter = false;

assert_eq!(
Into::<ldap_poller::Config>::into(config.ldap).attributes.get_attr_filter(),
vec!["*"]
);
}
}
1 change: 1 addition & 0 deletions tests/environment/config.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ ldap:
user_filter: "(objectClass=shadowAccount)"
timeout: 5
check_for_deleted_entries: true
use_attribute_filter: true
attributes:
first_name: "cn" # objectClass: person
last_name: "sn" # objectClass: person
Expand Down

0 comments on commit 75ed0bf

Please sign in to comment.