Add support for managing domain aliases from the yaml config file

This commit is contained in:
Daniel Berteaud 2019-10-31 11:16:16 +01:00
parent 4cf4ae59ae
commit 3e858dd880
2 changed files with 85 additions and 37 deletions

View File

@ -1,4 +1,4 @@
# LDAP synchronisation
# LDAP synchronisation and domain provisioning
This script brings a complete synchronization of user accounts and groups from an external LDAP server.
@ -12,11 +12,17 @@ The goals are :
* Handle email alias defined in LDAP, and translate them into aliases in Zimbra
* Allow objects (aliase, distribution list) to be created directly in Zimbra. Objects coming from LDAP are synchronized, including alias previously defined in LDAP which aren't anymore are removed from Zimbra. But aliases defined directly in Zimbra won't be touched. Same is true for distribution lists. So you can mix LDAP defined and Zimbra defined configuration
A few other features are included, like :
* Creating domains
* Creating / removing domain aliases
All from a simple yaml configuration file
## Configuration
The configuration is stored in a single file in YAML format. The script will look for a config at /opt/zimbra/conf/zmldapsync.yml or trhe one specified in the --config argument.
The configuration is stored in a single file in YAML format. The script will look for a config at /opt/zimbra/conf/zmldapsync.yml or the one specified in the --config argument.
The config has two main section :
The config has two main sections :
* general : settings which affects all domains, mainly to configure email notification in case of error
* domains : list of domain to sync, and the settings for each of them
@ -142,6 +148,10 @@ domains:
# If the domain in Zimbra exists but is not configured
# for external auth (either LDAP or AD), should this script configure it ?
setup_ldap_auth: True
# If defined, domain aliases will be added to / removed from Zimbra according to this list
domain_aliases:
- mail.corp2.com
- corp4.net
```
## Command line

View File

@ -84,35 +84,34 @@ DOMAIN: foreach my $domain ( keys $conf->{domains} ) {
$conf->{domains}->{$domain} = get_default_conf( $conf->{domains}->{$domain} );
# Search in Zimbra LDAP if the required domain exists
my $zim_domain_search = $zim_ldap->ldap->search(
filter => "(&(objectClass=zimbraDomain)(zimbraDomainName=$domain)(!(zimbraDomainAliasTargetId=*)))",
attrs => [
'zimbraDomainName',
'zimbraDomainType',
'zimbraId',
'zimbraAuthMechAdmin',
'zimbraAuthMech',
'zimbraAuthLdapSearchBindDn',
'zimbraAuthLdapSearchBindPassword',
'zimbraAuthLdapSearchFilter'
]
);
my $zim_domain_search = search_zim_domain($domain);
if ( not defined $zim_domain_search ) {
handle_error(
$domain,
'Zimbra domain lookup',
'Search returned an empty object'
);
next DOMAIN;
}
if ( $zim_domain_search->code ) {
handle_error(
$domain,
'Zimbra domain lookup',
$zim_domain_search->error
);
next DOMAIN
next DOMAIN;
}
# We must have exactly 1 result
if ( scalar $zim_domain_search->entries == 0 ) {
if ( yaml_bool($conf->{domains}->{$domain}->{zimbra}->{create_if_missing}) ) {
log_info( "Creating domain $domain" );
ZmClient::sendZmprovRequest( "createDomain $domain " .
send_zmprov_cmd( "createDomain $domain " .
build_domain_attrs($conf->{domains}->{$domain})
);
# Now that we have created the domain, lets lookup again
$zim_domain_search = search_zim_domain($domain);
} else {
handle_error(
$domain,
@ -148,23 +147,23 @@ DOMAIN: foreach my $domain ( keys $conf->{domains} ) {
}
}
# Now lookup for domain aliases defined in Zimbra
my $zim_domain_alias_search = $zim_ldap->ldap->search(
filter => "(&(objectClass=zimbraDomain)(zimbraDomainAliasTargetId=" . $domain_entry->{zimbraId} . "))"
);
if ( $zim_domain_alias_search->code ) {
handle_error(
$domain,
'Zimbra domain alias lookup',
$zim_domain_alias_search->error
);
next DOMAIN;
}
@{ $domain_entry->{zimbraDomainAliases} } = get_domain_aliases( $domain_entry );
$domain_entry->{zimbraDomainAliases} = [];
foreach my $alias ( $zim_domain_alias_search->entries ) {
push @{ $domain_entry->{zimbraDomainAliases} },
$alias->get_value('zimbraDomainName');
if ( defined $conf->{domains}->{$domain}->{zimbra}->{domain_aliases} ) {
log_verbose( "Comparing domain aliases" );
my $aliases_diff = Array::Diff->diff( $domain_entry->{zimbraDomainAliases}, $conf->{domains}->{$domain}->{zimbra}->{domain_aliases} );
foreach my $alias (@{ $aliases_diff->added } ) {
log_info( "Creating domain alias $alias for domain $domain" );
send_zmprov_cmd( "createAliasDomain $alias $domain" );
}
foreach my $alias (@{ $aliases_diff->deleted } ) {
log_info( "Removing domain alias $alias for domain $domain" );
send_zmprov_cmd( "deleteDomain $alias" );
}
# Make a new lookup if changes were made
if ( $aliases_diff->count > 0 ) {
@{ $domain_entry->{zimbraDomainAliases} } = get_domain_aliases( $domain_entry );
}
}
log_verbose( "Trying to connect to " .
@ -747,7 +746,7 @@ sub handle_error {
$exit = 255;
}
# ldap2hashref takes three args
# ldap2hashref takes four args
# * An LDAP search result
# * The attribute used as the key of objects
# * An optional array of attributes we want as an array, even if there's a single value
@ -868,6 +867,44 @@ sub parse_zimbra_notes {
return $return;
}
# Search for a specific domain
sub search_zim_domain {
my $dom = shift;
# Search in Zimbra LDAP if the required domain exists
my $zim_domain_search = $zim_ldap->ldap->search(
filter => "(&(objectClass=zimbraDomain)(zimbraDomainName=$dom)(!(zimbraDomainAliasTargetId=*)))",
attrs => [
'zimbraDomainName',
'zimbraDomainType',
'zimbraId',
'zimbraAuthMechAdmin',
'zimbraAuthMech',
'zimbraAuthLdapSearchBindDn',
'zimbraAuthLdapSearchBindPassword',
'zimbraAuthLdapSearchFilter'
]
);
return $zim_domain_search;
}
# Get a list of aliases for a domain
# Takes a hashref representing a domain entry as argument
sub get_domain_aliases {
my $dom = shift;
my @aliases = ();
# Now lookup for domain aliases defined in Zimbra
my $zim_domain_alias_search = $zim_ldap->ldap->search(
filter => "(&(objectClass=zimbraDomain)(zimbraDomainAliasTargetId=" . $dom->{zimbraId} . "))"
);
foreach my $alias ( $zim_domain_alias_search->entries ) {
push @aliases, $alias->get_value('zimbraDomainName');
}
return @aliases;
}
# Set default config values if missing
sub get_default_conf {
my $conf = shift;
@ -999,8 +1036,9 @@ sub get_default_conf {
}
$defaults->{zimbra} = {
create_if_missing => 0,
setup_ldap_auth => 0
create_if_missing => 0,
setup_ldap_auth => 0,
domain_aliases => undef,
};
# If some attribute mapping is defined in the provided conf