/*
* Copyright (c) 2016 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.auth.impl;
import com.emc.storageos.auth.SystemPropertyUtil;
import com.emc.storageos.auth.ldap.StorageOSLdapAuthenticationHandler;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.AuthnProvider;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.services.util.NamedScheduledThreadPoolExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class LdapProviderMonitor {
private static final Logger log = LoggerFactory.getLogger(LdapProviderMonitor.class);
private static final long MONITOR_INTERVAL_MIN = 10;
private static final String LDAP_MONITOR_NAME = "LdapProviderMonitor";
private ImmutableAuthenticationProviders providerList;
private DbClient dbClient;
private CoordinatorClient coordinator;
private NamedScheduledThreadPoolExecutor threadPoolExecutor = null;
public LdapProviderMonitor(CoordinatorClient coordinator, DbClient dbClient, ImmutableAuthenticationProviders providerList) {
this.coordinator = coordinator;
this.dbClient = dbClient;
this.providerList = providerList;
}
public void start() {
NamedScheduledThreadPoolExecutor threadPoolExecutor = new NamedScheduledThreadPoolExecutor(LDAP_MONITOR_NAME, 1);
threadPoolExecutor.scheduleAtFixedRate(new LdapMonitorWorker(), 0, MONITOR_INTERVAL_MIN, TimeUnit.MINUTES);
log.info("LdapProvider Monitor started.");
}
public void stop() {
if (threadPoolExecutor != null) {
threadPoolExecutor.shutdown();
}
}
public void setAuthnProviders(ImmutableAuthenticationProviders authnProviders) {
this.providerList = authnProviders;
}
private class LdapMonitorWorker implements Runnable {
@Override
public void run() {
log.info("Ldap Monitor Worker wake up ...");
try {
List<AuthenticationProvider> providers = null;
providers = providerList.getAuthenticationProviders();
log.info("Ldap Monitor Worker got provider list. Size is {}.", providers.size());
for (AuthenticationProvider provider : providers) {
if (!(provider.getHandler() instanceof StorageOSLdapAuthenticationHandler)) { // That's for AD or Ldap
log.info("Found a provider but is not ldap mode. Skipping ...");
continue;
}
log.info("Found a provider which is ldap mode.");
StorageOSLdapAuthenticationHandler handler = (StorageOSLdapAuthenticationHandler) provider.getHandler();
LdapServerList ldapServers = handler.getLdapServers();
List<LdapOrADServer> disconnectedServers = ldapServers.getDisconnectedServers();
log.info("Disconnected servers is {}", disconnectedServers);
AuthnProvider authnProvider = queryAuthnProviderFromDB(handler.getDomains());
// Do check.
List<LdapOrADServer> backServers = new ArrayList<>();
for (LdapOrADServer server : ldapServers.getDisconnectedServers()) {
log.info("Checking if server {}'s connection get back.", server);
boolean isGood = checkLdapServerConnectivity(authnProvider, server.getContextSource().getUrls()[0]);
if (isGood) {
backServers.add(server);
log.info("The AD or ldap server {} came back.", server);
}
}
for (LdapOrADServer backServer : backServers) {
ldapServers.markAsConnected(backServer);
}
}
} catch (Exception e) {
log.warn("Error to check ldap status. {}", e);
}
log.info("Ldap Monitor Worker done a cycle");
}
}
private boolean checkLdapServerConnectivity(AuthnProvider authnProvider, String serverUrl) {
int timeout = SystemPropertyUtil.getLdapConnectionTimeout(coordinator);
LdapContextSource contextSource = ImmutableAuthenticationProviders.createConfiguredLDAPContextSource(coordinator, authnProvider, timeout, serverUrl);
LdapTemplate template = new LdapTemplate(contextSource);
template.setIgnorePartialResultException(true);
try {
// authenticates manager credentials and performs the look up for the search base
template.lookup(new DistinguishedName(authnProvider.getSearchBase()));
return true;
} catch (Exception e) {
return false;
}
}
private AuthnProvider queryAuthnProviderFromDB(Set<String> domains) {
URIQueryResultList providers = new URIQueryResultList();
String domain = (String) domains.toArray()[0]; // Must have at lease one
try {
dbClient.queryByConstraint(AlternateIdConstraint.Factory.getAuthnProviderDomainConstraint(domain), providers);
Iterator<URI> it = providers.iterator();
while (it.hasNext()) {
URI providerURI = it.next();
AuthnProvider provider = dbClient.queryObject(AuthnProvider.class, providerURI);
if (provider != null && provider.getDisable() == false) {
return provider;
}
}
} catch (DatabaseException ex) {
log.error("Could not query for authn providers to check for existing domain {}", domain, ex);
throw ex;
}
return null;
}
}