DnsZoneRepositoryImpl.java
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bremersee.dccon.repository;
import static org.bremersee.dccon.repository.cli.CommandExecutorResponse.toExceptionMessage;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.extern.slf4j.Slf4j;
import org.bremersee.data.ldaptive.LdaptiveEntryMapper;
import org.bremersee.data.ldaptive.LdaptiveTemplate;
import org.bremersee.dccon.config.DomainControllerProperties;
import org.bremersee.dccon.model.DnsZone;
import org.bremersee.dccon.repository.cli.CommandExecutor;
import org.bremersee.dccon.repository.cli.CommandExecutorResponse;
import org.bremersee.dccon.repository.cli.CommandExecutorResponseParser;
import org.bremersee.dccon.repository.cli.CommandExecutorResponseValidator;
import org.bremersee.dccon.repository.ldap.DnsZoneLdapMapper;
import org.bremersee.exception.ServiceException;
import org.ldaptive.SearchFilter;
import org.ldaptive.SearchRequest;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
/**
* The dns zone repository.
*
* @author Christian Bremer
*/
@Profile("ldap")
@Component("dnsZoneRepository")
@Slf4j
public class DnsZoneRepositoryImpl extends AbstractRepository implements DnsZoneRepository {
private final List<Pattern> excludedZoneNamePatterns;
private LdaptiveEntryMapper<DnsZone> dnsZoneLdapMapper;
/**
* Instantiates a new dns zone repository.
*
* @param properties the properties
* @param ldapTemplateProvider the ldap template provider
*/
public DnsZoneRepositoryImpl(
final DomainControllerProperties properties,
final ObjectProvider<LdaptiveTemplate> ldapTemplateProvider) {
super(properties, ldapTemplateProvider.getIfAvailable());
this.dnsZoneLdapMapper = new DnsZoneLdapMapper(properties);
this.excludedZoneNamePatterns = properties.getExcludedZoneRegexList().stream()
.map(Pattern::compile).collect(Collectors.toList());
}
/**
* Sets dns zone ldap mapper.
*
* @param dnsZoneLdapMapper the dns zone ldap mapper
*/
@SuppressWarnings("unused")
public void setDnsZoneLdapMapper(final LdaptiveEntryMapper<DnsZone> dnsZoneLdapMapper) {
if (dnsZoneLdapMapper != null) {
this.dnsZoneLdapMapper = dnsZoneLdapMapper;
}
}
private boolean isNonExcludedDnsZone(final DnsZone zone) {
return zone != null && !isExcludedDnsZone(zone);
}
private boolean isNonExcludedDnsZone(final String zoneName) {
return zoneName != null && !isExcludedDnsZone(zoneName);
}
private boolean isExcludedDnsZone(final DnsZone zone) {
return zone != null && isExcludedDnsZone(zone.getName());
}
private boolean isExcludedDnsZone(final String zoneName) {
return zoneName != null && excludedZoneNamePatterns.stream()
.anyMatch(pattern -> pattern.matcher(zoneName).matches());
}
@Override
public boolean isDnsReverseZone(final String dnsZoneName) {
return getProperties().isReverseZone(dnsZoneName);
}
@Override
public Stream<DnsZone> findAll() {
final SearchRequest searchRequest = new SearchRequest(
getProperties().getDnsZoneBaseDn(),
new SearchFilter(getProperties().getDnsZoneFindAllFilter()));
searchRequest.setSearchScope(getProperties().getDnsZoneFindAllSearchScope());
return getLdapTemplate().findAll(searchRequest, dnsZoneLdapMapper)
.filter(this::isNonExcludedDnsZone);
}
@Override
public boolean exists(final String zoneName) {
return isNonExcludedDnsZone(zoneName)
&& getLdapTemplate().exists(DnsZone.builder().name(zoneName).build(), dnsZoneLdapMapper);
}
@Override
public Optional<DnsZone> findOne(final String zoneName) {
final SearchFilter searchFilter = new SearchFilter(getProperties().getDnsZoneFindOneFilter());
searchFilter.setParameter(0, zoneName);
final SearchRequest searchRequest = new SearchRequest(
getProperties().getDnsZoneBaseDn(),
searchFilter);
searchRequest.setSearchScope(getProperties().getDnsZoneFindOneSearchScope());
return getLdapTemplate()
.findOne(searchRequest, dnsZoneLdapMapper)
.filter(this::isNonExcludedDnsZone);
}
@Override
public DnsZone save(final String zoneName) {
if (isExcludedDnsZone(zoneName)) {
throw ServiceException.badRequest(
"Zone name is not allowed.",
"org.bremersee:dc-con-app:bc02abb3-f5d9-4a95-9761-98def37d12a9");
}
return findOne(zoneName)
.orElseGet(() -> doSave(zoneName));
}
/**
* Save dns zone.
*
* @param zoneName the zone name
* @return the dns zone
*/
DnsZone doSave(final String zoneName) {
return execDnsZoneCmd(
"zonecreate",
zoneName, response -> findOne(zoneName)
.orElseThrow(() -> ServiceException.internalServerError(
"msg=[Saving dns zone failed.] "
+ CommandExecutorResponse.toExceptionMessage(response),
"org.bremersee:dc-con-app:905a21c0-0ab9-4562-a83f-b849dbbea6c0")));
}
@Override
public boolean delete(final String zoneName) {
if (exists(zoneName)) {
doDelete(zoneName);
return true;
}
return false;
}
/**
* Delete dns zone.
*
* @param zoneName the zone name
*/
void doDelete(final String zoneName) {
execDnsZoneCmd(
"zonedelete",
zoneName,
(CommandExecutorResponseValidator) response -> {
if (exists(zoneName)) {
throw ServiceException.internalServerError(
"msg=[Deleting dns zone failed.] " + toExceptionMessage(response),
"org.bremersee:dc-con-app:346a54dd-c882-4c41-8503-7089928aeaa3");
}
});
}
private <T> T execDnsZoneCmd(
final String dnsCommand,
final String zoneName,
final CommandExecutorResponseParser<T> parser) {
kinit();
final List<String> commands = new ArrayList<>();
sudo(commands);
commands.add(getProperties().getSambaToolBinary());
commands.add("dns");
commands.add(dnsCommand);
commands.add(getProperties().getNameServerHost());
commands.add(zoneName);
auth(commands);
return CommandExecutor.exec(
commands, null, getProperties().getSambaToolExecDir(), parser);
}
}