/*******************************************************************************
* Copyright (c) 2010-2016 SAP AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.skalli.core.user.ldap;
import java.text.MessageFormat;
import java.util.Hashtable;
import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.eclipse.skalli.core.destination.DestinationConfig;
import org.eclipse.skalli.core.destination.DestinationsConfig;
import org.eclipse.skalli.services.configuration.Configurations;
import org.eclipse.skalli.services.user.ldap.LdapContextProvider;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.jndi.JNDIConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DefaultLdapContextProvider implements LdapContextProvider {
private final static Logger LOG = LoggerFactory.getLogger(DefaultLdapContextProvider.class);
private static final String LDAPS = "ldaps://"; //$NON-NLS-1$
private static final String SIMPLE_AUTHENTICATION = "simple"; //$NON-NLS-1$
private static final String NO_SSL_VERIFY = "NO_SSL_VERIFY"; //$NON-NLS-1$
private static final String JNDI_SOCKET_FACTORY = "java.naming.ldap.factory.socket"; //$NON-NLS-1$
private static final String DEFAULT_CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory"; //$NON-NLS-1$
private static final String READ_TIMEOUT = "com.sun.jndi.ldap.read.timeout";//$NON-NLS-1$
private static final String USE_CONNECTION_POOLING = "com.sun.jndi.ldap.connect.pool"; //$NON-NLS-1$
private static final long DEFAULT_READ_TIMEOUT = 30000L;
protected void activate(ComponentContext context) {
LOG.info(MessageFormat.format("[LdapContextProvider][default] {0} : activated", //$NON-NLS-1$
(String) context.getProperties().get(ComponentConstants.COMPONENT_NAME)));
}
protected void deactivate(ComponentContext context) {
LOG.info(MessageFormat.format("[LdapContextProvider][default] {0} : deactivated", //$NON-NLS-1$
(String) context.getProperties().get(ComponentConstants.COMPONENT_NAME)));
}
@Override
public String getId() {
return "default"; //$NON-NLS-1$
}
@Override
public LdapContext getLdapContext(String destination) throws NamingException, AuthenticationException {
DestinationsConfig destinationsConfig = Configurations.getConfiguration(DestinationsConfig.class);
if (destinationsConfig == null) {
throw new NamingException("No LDAP destination available");
}
DestinationConfig destinationConfig = destinationsConfig.getDestination(destination);
if (destinationConfig == null) {
throw new NamingException("No LDAP destination available");
}
String providerUrl = destinationConfig.getUrlPattern();
if (StringUtils.isBlank(providerUrl)) {
throw new NamingException("No LDAP server configured");
}
if (StringUtils.isBlank(destinationConfig.getUser()) || StringUtils.isBlank(destinationConfig.getPassword())) {
throw new AuthenticationException("No LDAP credentials available");
}
String ctxFactory = destinationConfig.getProperty(Context.INITIAL_CONTEXT_FACTORY);
if (StringUtils.isBlank(ctxFactory)) {
ctxFactory = DEFAULT_CONTEXT_FACTORY;
}
String authentication = destinationConfig.getAuthentication();
if (StringUtils.isBlank(authentication)) {
authentication = SIMPLE_AUTHENTICATION;
}
Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.INITIAL_CONTEXT_FACTORY, ctxFactory);
env.put(Context.PROVIDER_URL, providerUrl);
env.put(Context.SECURITY_PRINCIPAL, destinationConfig.getUser());
env.put(Context.SECURITY_CREDENTIALS, destinationConfig.getPassword());
env.put(Context.SECURITY_AUTHENTICATION, authentication);
String referral = destinationConfig.getProperty(Context.REFERRAL);
if (StringUtils.isNotBlank(referral)) {
env.put(Context.REFERRAL, referral);
}
if (providerUrl.startsWith(LDAPS)) {
env.put(Context.SECURITY_PROTOCOL, "ssl"); //$NON-NLS-1$
if (BooleanUtils.toBoolean(destinationConfig.getProperty(NO_SSL_VERIFY))) {
env.put(JNDI_SOCKET_FACTORY, LDAPTrustAllSocketFactory.class.getName());
}
}
// Gemini-specific properties
env.put(JNDIConstants.BUNDLE_CONTEXT,
FrameworkUtil.getBundle(DefaultLdapContextProvider.class).getBundleContext());
// com.sun.jndi.ldap.LdapCtxFactory specific properties
long readTimeout = NumberUtils.toLong(destinationConfig.getProperty(READ_TIMEOUT), DEFAULT_READ_TIMEOUT);
env.put(READ_TIMEOUT, Long.toString(readTimeout));
env.put(USE_CONNECTION_POOLING, "true"); //$NON-NLS-1$
// extremly ugly classloading workaround:
// com.sun.jndi.ldap.LdapCtxFactory uses Class.forName() to load the socket factory, shame on them!
InitialLdapContext ctx = null;
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(LDAPTrustAllSocketFactory.class.getClassLoader());
ctx = new InitialLdapContext(env, null);
} finally {
if (classloader != null) {
Thread.currentThread().setContextClassLoader(classloader);
}
}
return ctx;
}
}