/**
* Copyright (c) Codice Foundation
* <p/>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p/>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.ldap.ldaplogin;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.CONNECTION_PASSWORD;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.CONNECTION_URL;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.CONNECTION_USERNAME;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.ROLE_BASE_DN;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.ROLE_FILTER;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.ROLE_NAME_ATTRIBUTE;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.ROLE_SEARCH_SUBTREE;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.SSL_STARTTLS;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.USER_FILTER;
import static ddf.ldap.ldaplogin.SslLdapLoginModule.USER_SEARCH_SUBTREE;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.apache.karaf.jaas.config.impl.Module;
import org.codice.ddf.configuration.PropertyResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Registers LDAP as a JAAS realm.
*/
public class LdapLoginConfig {
public static final String LDAP_BIND_USER_DN = "ldapBindUserDn";
public static final String LDAP_BIND_USER_PASS = "ldapBindUserPass";
public static final String LDAP_URL = "ldapUrl";
public static final String BIND_METHOD = "bindMethod";
public static final String USER_BASE_DN = "userBaseDn";
public static final String GROUP_BASE_DN = "groupBaseDn";
public static final String START_TLS = "startTls";
public static final String REALM = "realm";
public static final String KDC_ADDRESS = "kdcAddress";
private static final String SUFFICIENT_FLAG = "sufficient";
private static final String USER_NAME_ATTRIBUTE = "userNameAttribute";
private static final Logger LOGGER = LoggerFactory.getLogger(LdapLoginConfig.class);
private static final String LDAP_MODULE = ddf.ldap.ldaplogin.SslLdapLoginModule.class.getName();
private String id = "LDAP:" + UUID.randomUUID()
.toString();
private Map<String, Object> ldapProperties = new HashMap<>();
private LdapService ldapService;
/**
* Update method that receives new properties.
*
* @param props Map of properties.
*/
public void update(Map<String, ?> props) {
if (props != null) {
LOGGER.debug("Received an updated set of configurations for the LDAP Login Config.");
// create modules from the newly updated config
Module ldapModule = createLdapModule(props);
ldapService.update(ldapModule);
}
}
/**
* Creates a new module with the given properties.
*
* @param properties Map of properties.
* @return newly created module.
*/
private Module createLdapModule(Map<String, ?> properties) {
Module ldapModule = new Module();
ldapModule.setClassName(LDAP_MODULE);
ldapModule.setFlags(SUFFICIENT_FLAG);
ldapModule.setName(id);
Properties props = new Properties();
props.put(CONNECTION_USERNAME, properties.get(LDAP_BIND_USER_DN));
props.put(CONNECTION_PASSWORD, properties.get(LDAP_BIND_USER_PASS));
props.put(CONNECTION_URL,
new PropertyResolver((String) properties.get(LDAP_URL)).toString());
final Object userBaseDn = properties.get(USER_BASE_DN);
props.put(SslLdapLoginModule.USER_BASE_DN, userBaseDn);
final Object userNameAttribute = properties.get(USER_NAME_ATTRIBUTE);
props.put(USER_FILTER, String.format("(%s=%%u)", userNameAttribute));
props.put(USER_SEARCH_SUBTREE, "true");
props.put(ROLE_BASE_DN, properties.get(GROUP_BASE_DN));
props.put(ROLE_FILTER, String.format("(member=%s=%%u,%s)", userNameAttribute, userBaseDn));
props.put(ROLE_NAME_ATTRIBUTE, "cn");
props.put(ROLE_SEARCH_SUBTREE, "true");
props.put("authentication", "simple");
props.put("ssl.protocol", "TLS");
props.put("ssl.algorithm", "SunX509");
props.put(SSL_STARTTLS, properties.get(START_TLS));
props.put(BIND_METHOD, properties.get(BIND_METHOD));
props.put(REALM, (properties.get(REALM) != null) ? properties.get(REALM) : "");
props.put(KDC_ADDRESS,
(properties.get(KDC_ADDRESS) != null) ? properties.get(KDC_ADDRESS) : "");
if ("GSSAPI SASL".equals(properties.get(BIND_METHOD)) && (
StringUtils.isEmpty((String) properties.get(REALM)) || StringUtils.isEmpty(
(String) properties.get(KDC_ADDRESS)))) {
LOGGER.warn(
"LDAP connection will fail. GSSAPI SASL connection requires Kerberos Realm and KDC Address.");
}
ldapModule.setOptions(props);
return ldapModule;
}
String getId() {
return id;
}
public void setLdapBindUserDn(String ldapBindUserDn) {
LOGGER.trace("setLdapBindUserDn called: {}", ldapBindUserDn);
ldapProperties.put(LDAP_BIND_USER_DN, ldapBindUserDn);
}
public void setLdapBindUserPass(String bindUserPass) {
LOGGER.trace("setLdapBindUserPass called: {}", bindUserPass);
ldapProperties.put(LDAP_BIND_USER_PASS, bindUserPass);
}
public void setLdapUrl(String ldapUrl) {
LOGGER.trace("setLdapUrl called: {}", ldapUrl);
ldapProperties.put(LDAP_URL, ldapUrl);
}
public void setUserBaseDn(String userBaseDn) {
LOGGER.trace("setUserBaseDn called: {}", userBaseDn);
ldapProperties.put(USER_BASE_DN, userBaseDn);
}
public void setGroupBaseDn(String groupBaseDn) {
LOGGER.trace("setGroupBaseDn called: {}", groupBaseDn);
ldapProperties.put(GROUP_BASE_DN, groupBaseDn);
}
public void setStartTls(boolean startTls) {
LOGGER.trace("Setting startTls: {}", startTls);
ldapProperties.put(START_TLS, String.valueOf(startTls));
}
public void setStartTls(String startTls) {
LOGGER.trace("Setting startTls: {}", startTls);
ldapProperties.put(START_TLS, startTls);
}
public void setUserNameAttribute(String userNameAttribute) {
LOGGER.trace("setUserNameAttribute called: {}", userNameAttribute);
ldapProperties.put(USER_NAME_ATTRIBUTE, userNameAttribute);
}
public void setBindMethod(String bindMethod) {
LOGGER.trace("setBindMethod: {}", bindMethod);
ldapProperties.put(BIND_METHOD, bindMethod);
}
public void setRealm(String realm) {
LOGGER.trace("setRealm: {}", realm);
ldapProperties.put(REALM, realm);
}
public void setKdcAddress(String kdcAddress) {
LOGGER.trace("setKdcAddress: {}", kdcAddress);
ldapProperties.put(KDC_ADDRESS, kdcAddress);
}
public void configure() {
LOGGER.trace("configure called - calling update");
update(ldapProperties);
}
public void destroy(int arg) {
LOGGER.trace("configure called - calling delete");
ldapService.delete(id);
}
public void setLdapService(LdapService ldapService) {
this.ldapService = ldapService;
}
}