diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/AbstractLdapProvider.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/AbstractLdapProvider.java index 3e8c52d2ee..501eb5891a 100644 --- a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/AbstractLdapProvider.java +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/AbstractLdapProvider.java @@ -30,11 +30,13 @@ import org.apache.nifi.authorization.exception.ProviderDestructionException; import org.apache.nifi.util.FormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ldap.CommunicationException; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.ldap.authentication.AbstractLdapAuthenticationProvider; +import org.springframework.security.ldap.userdetails.LdapUserDetails; /** * Abstract LDAP based implementation of a login identity provider. @@ -59,7 +61,7 @@ public abstract class AbstractLdapProvider implements LoginIdentityProvider { try { expiration = FormatUtils.getTimeDuration(rawExpiration, TimeUnit.MILLISECONDS); - } catch (final NumberFormatException nfe) { + } catch (final IllegalArgumentException iae) { throw new ProviderCreationException(String.format("The Expiration Duration '%s' is not a valid time duration", rawExpiration)); } @@ -75,15 +77,23 @@ public abstract class AbstractLdapProvider implements LoginIdentityProvider { } try { + // perform the authentication final UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword()); final Authentication authentication = provider.authenticate(token); - return new AuthenticationResponse(authentication.getPrincipal().toString(), credentials.getUsername()); - } catch (final AuthenticationServiceException ase) { - logger.error(ase.getMessage()); - if (logger.isDebugEnabled()) { - logger.debug(StringUtils.EMPTY, ase); + + // attempt to get the ldap user details to get the DN + if (authentication.getPrincipal() instanceof LdapUserDetails) { + final LdapUserDetails userDetails = (LdapUserDetails) authentication.getPrincipal(); + return new AuthenticationResponse(userDetails.getDn(), credentials.getUsername()); + } else { + return new AuthenticationResponse(authentication.getName(), credentials.getUsername()); } - throw new IdentityAccessException("Unable to query the configured directory server. See the logs for additional details.", ase); + } catch (final CommunicationException | AuthenticationServiceException e) { + logger.error(e.getMessage()); + if (logger.isDebugEnabled()) { + logger.debug(StringUtils.EMPTY, e); + } + throw new IdentityAccessException("Unable to query the configured directory server. See the logs for additional details.", e); } catch (final BadCredentialsException bce) { throw new InvalidLoginCredentialsException(bce.getMessage(), bce); } diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java index 7d2a7d9e6a..3c26d9fc05 100644 --- a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java @@ -22,12 +22,16 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.authentication.LoginIdentityProviderConfigurationContext; import org.apache.nifi.authorization.exception.ProviderCreationException; import org.apache.nifi.security.util.SslContextFactory; import org.apache.nifi.security.util.SslContextFactory.ClientAuth; +import org.apache.nifi.util.FormatUtils; import org.springframework.ldap.core.support.AbstractTlsDirContextAuthenticationStrategy; import org.springframework.ldap.core.support.DefaultTlsDirContextAuthenticationStrategy; import org.springframework.ldap.core.support.DigestMd5DirContextAuthenticationStrategy; @@ -50,12 +54,43 @@ public class LdapProvider extends AbstractLdapProvider { protected AbstractLdapAuthenticationProvider getLdapAuthenticationProvider(LoginIdentityProviderConfigurationContext configurationContext) throws ProviderCreationException { final LdapContextSource context = new LdapContextSource(); + final Map baseEnvironment = new HashMap<>(); + + // connection time out + final String rawConnectTimeout = configurationContext.getProperty("Connect Timeout"); + if (StringUtils.isNotBlank(rawConnectTimeout)) { + try { + final Long connectTimeout = FormatUtils.getTimeDuration(rawConnectTimeout, TimeUnit.MILLISECONDS); + baseEnvironment.put("com.sun.jndi.ldap.connect.timeout", connectTimeout.toString()); + } catch (final IllegalArgumentException iae) { + throw new ProviderCreationException(String.format("The Connect Timeout '%s' is not a valid time duration", rawConnectTimeout)); + } + } + + // read time out + final String rawReadTimeout = configurationContext.getProperty("Read Timeout"); + if (StringUtils.isNotBlank(rawReadTimeout)) { + try { + final Long readTimeout = FormatUtils.getTimeDuration(rawReadTimeout, TimeUnit.MILLISECONDS); + baseEnvironment.put("com.sun.jndi.ldap.read.timeout", readTimeout.toString()); + } catch (final IllegalArgumentException iae) { + throw new ProviderCreationException(String.format("The Read Timeout '%s' is not a valid time duration", rawReadTimeout)); + } + } + + // set the base environment is necessary + if (!baseEnvironment.isEmpty()) { + context.setBaseEnvironmentProperties(baseEnvironment); + } + + // authentication strategy final String rawAuthenticationStrategy = configurationContext.getProperty("Authentication Strategy"); final LdapAuthenticationStrategy authenticationStrategy; try { authenticationStrategy = LdapAuthenticationStrategy.valueOf(rawAuthenticationStrategy); } catch (final IllegalArgumentException iae) { - throw new ProviderCreationException(String.format("Unrecgonized authentication strategy '%s'", rawAuthenticationStrategy)); + throw new ProviderCreationException(String.format("Unrecgonized authentication strategy '%s'. Possible values are [%s]", + rawAuthenticationStrategy, StringUtils.join(LdapAuthenticationStrategy.values(), ", "))); } switch (authenticationStrategy) { @@ -63,8 +98,8 @@ public class LdapProvider extends AbstractLdapProvider { context.setAnonymousReadOnly(true); break; default: - final String userDn = configurationContext.getProperty("Bind DN"); - final String password = configurationContext.getProperty("Bind Password"); + final String userDn = configurationContext.getProperty("Manager DN"); + final String password = configurationContext.getProperty("Manager Password"); context.setUserDn(userDn); context.setPassword(password); @@ -122,6 +157,20 @@ public class LdapProvider extends AbstractLdapProvider { break; } + // referrals + final String rawReferralStrategy = configurationContext.getProperty("Referral Strategy"); + + final ReferralStrategy referralStrategy; + try { + referralStrategy = ReferralStrategy.valueOf(rawReferralStrategy); + } catch (final IllegalArgumentException iae) { + throw new ProviderCreationException(String.format("Unrecgonized authentication strategy '%s'. Possible values are [%s]", + rawAuthenticationStrategy, StringUtils.join(ReferralStrategy.values(), ", "))); + } + + context.setReferral(referralStrategy.toString()); + + // url final String url = configurationContext.getProperty("Url"); if (StringUtils.isBlank(url)) { @@ -131,6 +180,7 @@ public class LdapProvider extends AbstractLdapProvider { // connection context.setUrl(url); + // search criteria final String userSearchBase = configurationContext.getProperty("User Search Base"); final String userSearchFilter = configurationContext.getProperty("User Search Filter"); @@ -138,7 +188,6 @@ public class LdapProvider extends AbstractLdapProvider { throw new ProviderCreationException("LDAP identity provider 'User Search Base' and 'User Search Filter' must be specified."); } - // query final LdapUserSearch userSearch = new FilterBasedLdapUserSearch(userSearchBase, userSearchFilter, context); // bind @@ -154,6 +203,7 @@ public class LdapProvider extends AbstractLdapProvider { } // create the underlying provider - return new LdapAuthenticationProvider(authenticator); + final LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(authenticator); + return ldapAuthenticationProvider; } } diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/ReferralStrategy.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/ReferralStrategy.java new file mode 100644 index 0000000000..f4c513153c --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/ReferralStrategy.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.nifi.ldap; + +/** + * + */ +public enum ReferralStrategy { + + FOLLOW("follow"), + INGORE("ignore"), + THROW("throw"); + + private final String value; + + private ReferralStrategy(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + +}