Return-Path: X-Original-To: apmail-nifi-commits-archive@minotaur.apache.org Delivered-To: apmail-nifi-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E22EA18B3C for ; Mon, 23 Nov 2015 20:46:13 +0000 (UTC) Received: (qmail 76149 invoked by uid 500); 23 Nov 2015 20:46:13 -0000 Delivered-To: apmail-nifi-commits-archive@nifi.apache.org Received: (qmail 76086 invoked by uid 500); 23 Nov 2015 20:46:13 -0000 Mailing-List: contact commits-help@nifi.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@nifi.apache.org Delivered-To: mailing list commits@nifi.apache.org Received: (qmail 75152 invoked by uid 99); 23 Nov 2015 20:46:13 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 23 Nov 2015 20:46:13 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 33F24E0998; Mon, 23 Nov 2015 20:46:13 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: mcgilman@apache.org To: commits@nifi.apache.org Date: Mon, 23 Nov 2015 20:46:51 -0000 Message-Id: In-Reply-To: <8b4de3bbc1fb4077b05d8ef2c109ff8f@git.apache.org> References: <8b4de3bbc1fb4077b05d8ef2c109ff8f@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [40/50] [abbrv] nifi git commit: NIFI-655: - Refactoring web security to use Spring Security Java Configuration. - Introducing security in Web UI in order to get JWT. http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-storage.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-storage.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-storage.js new file mode 100644 index 0000000..7b0c3f6 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-storage.js @@ -0,0 +1,172 @@ +/* + * 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. + */ + +/* global nf, d3 */ + +nf.Storage = (function () { + + // Store items for two days before being eligible for removal. + var TWO_DAYS = nf.Common.MILLIS_PER_DAY * 2; + + /** + * Checks the expiration for the specified entry. + * + * @param {object} entry + * @returns {boolean} + */ + var checkExpiration = function (entry) { + if (nf.Common.isDefinedAndNotNull(entry.expires)) { + // get the expiration + var expires = new Date(entry.expires); + var now = new Date(); + + // return whether the expiration date has passed + return expires.valueOf() < now.valueOf(); + } else { + return false; + } + }; + + /** + * Gets an enty for the key. The entry expiration is not checked. + * + * @param {string} key + */ + var getEntry = function (key) { + try { + // parse the entry + var entry = JSON.parse(localStorage.getItem(key)); + + // ensure the entry and item are present + if (nf.Common.isDefinedAndNotNull(entry)) { + return entry; + } else { + return null; + } + } catch (e) { + return null; + } + }; + + return { + /** + * Initializes the storage. Items will be persisted for two days. Once the scripts runs + * thereafter, all eligible items will be removed. This strategy does not support persistence. + */ + init: function () { + for (var i = 0; i < localStorage.length; i++) { + try { + // get the next item + var key = localStorage.key(i); + + // attempt to get the item which will expire if necessary + nf.Storage.getItem(key); + } catch (e) { + } + } + }, + + /** + * Stores the specified item. + * + * @param {string} key + * @param {object} item + * @param {integer} expires + */ + setItem: function (key, item, expires) { + // calculate the expiration + expires = nf.Common.isDefinedAndNotNull(expires) ? expires : new Date().valueOf() + TWO_DAYS; + + // create the entry + var entry = { + expires: expires, + item: item + }; + + // store the item + localStorage.setItem(key, JSON.stringify(entry)); + }, + + /** + * Returns whether there is an entry for this key. This will not check the expiration. If + * the entry is expired, it will return null on a subsequent getItem invocation. + * + * @param {string} key + * @returns {boolean} + */ + hasItem: function (key) { + return getEntry(key) !== null; + }, + + /** + * Gets the item with the specified key. If an item with this key does + * not exist, null is returned. If an item exists but cannot be parsed + * or is malformed/unrecognized, null is returned. + * + * @param {type} key + */ + getItem: function (key) { + var entry = getEntry(key); + if (entry === null) { + return null; + } + + // if the entry is expired, drop it and return null + if (checkExpiration(entry)) { + nf.Storage.removeItem(key); + return null; + } + + // if the entry has the specified field return its value + if (nf.Common.isDefinedAndNotNull(entry['item'])) { + return entry['item']; + } else { + return null; + } + }, + + /** + * Gets the expiration for the specified item. This will not check the expiration. If + * the entry is expired, it will return null on a subsequent getItem invocation. + * + * @param {string} key + * @returns {integer} + */ + getItemExpiration: function (key) { + var entry = getEntry(key); + if (entry === null) { + return null; + } + + // if the entry has the specified field return its value + if (nf.Common.isDefinedAndNotNull(entry['expires'])) { + return entry['expires']; + } else { + return null; + } + }, + + /** + * Removes the item with the specified key. + * + * @param {type} key + */ + removeItem: function (key) { + localStorage.removeItem(key); + } + }; +}()); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js index 0edbe08..876e06d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/provenance/nf-provenance.js @@ -174,6 +174,8 @@ nf.Provenance = (function () { * Initializes the status page. */ init: function () { + nf.Storage.init(); + // load the users authorities and detect if the NiFi is clustered $.when(loadControllerConfig(), loadAuthorities(), detectedCluster()).done(function () { // create the provenance table http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js index 97f8626..4f06662 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/summary/nf-summary.js @@ -128,6 +128,8 @@ nf.Summary = (function () { * Initializes the status page. */ init: function () { + nf.Storage.init(); + // intialize the summary table initializeSummaryTable().done(function () { // load the table http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates.js index b55bee2..678e352 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/templates/nf-templates.js @@ -204,6 +204,8 @@ nf.Templates = (function () { * Initializes the templates page. */ init: function () { + nf.Storage.init(); + // load the users authorities loadAuthorities().done(function () { http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users.js index 96f73a5..9364aec 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/users/nf-users.js @@ -116,6 +116,8 @@ nf.Users = (function () { * Initializes the counters page. */ init: function () { + nf.Storage.init(); + // load the users authorities loadAuthorities().done(function () { // create the counters table http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers-nar/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers-nar/pom.xml b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers-nar/pom.xml new file mode 100644 index 0000000..59681b9 --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers-nar/pom.xml @@ -0,0 +1,32 @@ + + + + 4.0.0 + + org.apache.nifi + nifi-ldap-iaa-providers-bundle + 0.3.1-SNAPSHOT + + nifi-ldap-iaa-providers-nar + nar + + + org.apache.nifi + nifi-ldap-iaa-providers + + + nifi-ldap-iaa-providers-nar + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml new file mode 100644 index 0000000..5cbd6f9 --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/pom.xml @@ -0,0 +1,60 @@ + + + + 4.0.0 + + org.apache.nifi + nifi-ldap-iaa-providers-bundle + 0.3.1-SNAPSHOT + + nifi-ldap-iaa-providers + jar + + + org.apache.nifi + nifi-api + + + org.apache.nifi + nifi-utils + + + org.apache.nifi + nifi-security-utils + + + org.springframework.security + spring-security-ldap + + + org.springframework + spring-beans + + + org.springframework + spring-context + + + org.springframework + spring-tx + + + org.apache.commons + commons-lang3 + + + nifi-ldap-iaa-providers + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java new file mode 100644 index 0000000..7124ce1 --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapAuthenticationStrategy.java @@ -0,0 +1,27 @@ +/* + * 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 LdapAuthenticationStrategy { + + ANONYMOUS, + SIMPLE, + START_TLS +} http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..4dc7ea4 --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/LdapProvider.java @@ -0,0 +1,279 @@ +/* + * 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; + +import java.io.IOException; +import java.security.KeyManagementException; +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.AuthenticationResponse; +import org.apache.nifi.authentication.LoginCredentials; +import org.apache.nifi.authentication.LoginIdentityProvider; +import org.apache.nifi.authentication.LoginIdentityProviderConfigurationContext; +import org.apache.nifi.authentication.LoginIdentityProviderInitializationContext; +import org.apache.nifi.authentication.exception.IdentityAccessException; +import org.apache.nifi.authentication.exception.InvalidLoginCredentialsException; +import org.apache.nifi.authorization.exception.ProviderCreationException; +import org.apache.nifi.authorization.exception.ProviderDestructionException; +import org.apache.nifi.security.util.SslContextFactory; +import org.apache.nifi.security.util.SslContextFactory.ClientAuth; +import org.apache.nifi.util.FormatUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.ldap.CommunicationException; +import org.springframework.ldap.core.support.AbstractTlsDirContextAuthenticationStrategy; +import org.springframework.ldap.core.support.DefaultTlsDirContextAuthenticationStrategy; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy; +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.authentication.BindAuthenticator; +import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; +import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; +import org.springframework.security.ldap.search.LdapUserSearch; +import org.springframework.security.ldap.userdetails.LdapUserDetails; + +/** + * Abstract LDAP based implementation of a login identity provider. + */ +public class LdapProvider implements LoginIdentityProvider { + + private static final Logger logger = LoggerFactory.getLogger(LdapProvider.class); + + private AbstractLdapAuthenticationProvider provider; + private String issuer; + private long expiration; + + @Override + public final void initialize(final LoginIdentityProviderInitializationContext initializationContext) throws ProviderCreationException { + this.issuer = getClass().getSimpleName(); + } + + @Override + public final void onConfigured(final LoginIdentityProviderConfigurationContext configurationContext) throws ProviderCreationException { + final String rawExpiration = configurationContext.getProperty("Authentication Expiration"); + if (StringUtils.isBlank(rawExpiration)) { + throw new ProviderCreationException("The Authentication Expiration must be specified."); + } + + try { + expiration = FormatUtils.getTimeDuration(rawExpiration, TimeUnit.MILLISECONDS); + } catch (final IllegalArgumentException iae) { + throw new ProviderCreationException(String.format("The Expiration Duration '%s' is not a valid time duration", rawExpiration)); + } + + final LdapContextSource context = new LdapContextSource(); + + final Map baseEnvironment = new HashMap<>(); + + // connect/read time out + setTimeout(configurationContext, baseEnvironment, "Connect Timeout", "com.sun.jndi.ldap.connect.timeout"); + setTimeout(configurationContext, baseEnvironment, "Read Timeout", "com.sun.jndi.ldap.read.timeout"); + + // 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("Unrecognized authentication strategy '%s'. Possible values are [%s]", + rawAuthenticationStrategy, StringUtils.join(LdapAuthenticationStrategy.values(), ", "))); + } + + switch (authenticationStrategy) { + case ANONYMOUS: + context.setAnonymousReadOnly(true); + break; + default: + final String userDn = configurationContext.getProperty("Manager DN"); + final String password = configurationContext.getProperty("Manager Password"); + + context.setUserDn(userDn); + context.setPassword(password); + + switch (authenticationStrategy) { + case SIMPLE: + context.setAuthenticationStrategy(new SimpleDirContextAuthenticationStrategy()); + break; + case START_TLS: + final AbstractTlsDirContextAuthenticationStrategy tlsAuthenticationStrategy = new DefaultTlsDirContextAuthenticationStrategy(); + + // shutdown gracefully + final String rawShutdownGracefully = configurationContext.getProperty("TLS - Shutdown Gracefully"); + if (StringUtils.isNotBlank(rawShutdownGracefully)) { + final boolean shutdownGracefully = Boolean.TRUE.toString().equalsIgnoreCase(rawShutdownGracefully); + tlsAuthenticationStrategy.setShutdownTlsGracefully(shutdownGracefully); + } + + final String rawKeystore = configurationContext.getProperty("TLS - Keystore"); + final String rawKeystorePassword = configurationContext.getProperty("TLS - Keystore Password"); + final String rawKeystoreType = configurationContext.getProperty("TLS - Keystore Type"); + final String rawTruststore = configurationContext.getProperty("TLS - Truststore"); + final String rawTruststorePassword = configurationContext.getProperty("TLS - Truststore Password"); + final String rawTruststoreType = configurationContext.getProperty("TLS - Truststore Type"); + final String rawClientAuth = configurationContext.getProperty("TLS - Client Auth"); + final String rawProtocol = configurationContext.getProperty("TLS - Protocol"); + + final ClientAuth clientAuth; + if (StringUtils.isBlank(rawClientAuth)) { + clientAuth = ClientAuth.NONE; + } else { + try { + clientAuth = ClientAuth.valueOf(rawClientAuth); + } catch (final IllegalArgumentException iae) { + throw new ProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]", + rawClientAuth, StringUtils.join(ClientAuth.values(), ", "))); + } + } + + try { + final SSLContext sslContext; + if (StringUtils.isBlank(rawKeystore)) { + sslContext = SslContextFactory.createTrustSslContext(rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, rawProtocol); + } else { + if (StringUtils.isBlank(rawTruststore)) { + sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType, rawProtocol); + } else { + sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType, + rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, clientAuth, rawProtocol); + } + } + tlsAuthenticationStrategy.setSslSocketFactory(sslContext.getSocketFactory()); + } catch (final KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyManagementException | IOException e) { + throw new ProviderCreationException(e.getMessage(), e); + } + + context.setAuthenticationStrategy(tlsAuthenticationStrategy); + break; + } + 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)) { + throw new ProviderCreationException("LDAP identity provider 'Url' must be specified."); + } + + // connection + context.setUrl(url); + + // search criteria + final String userSearchBase = configurationContext.getProperty("User Search Base"); + final String userSearchFilter = configurationContext.getProperty("User Search Filter"); + + if (StringUtils.isBlank(userSearchBase) || StringUtils.isBlank(userSearchFilter)) { + throw new ProviderCreationException("LDAP identity provider 'User Search Base' and 'User Search Filter' must be specified."); + } + + final LdapUserSearch userSearch = new FilterBasedLdapUserSearch(userSearchBase, userSearchFilter, context); + + // bind + final BindAuthenticator authenticator = new BindAuthenticator(context); + authenticator.setUserSearch(userSearch); + + try { + // handling initializing beans + context.afterPropertiesSet(); + authenticator.afterPropertiesSet(); + } catch (final Exception e) { + throw new ProviderCreationException(e.getMessage(), e); + } + + // create the underlying provider + provider = new LdapAuthenticationProvider(authenticator); + } + + private void setTimeout(final LoginIdentityProviderConfigurationContext configurationContext, + final Map baseEnvironment, + final String configurationProperty, + final String environmentKey) { + + final String rawTimeout = configurationContext.getProperty(configurationProperty); + if (StringUtils.isNotBlank(rawTimeout)) { + try { + final Long timeout = FormatUtils.getTimeDuration(rawTimeout, TimeUnit.MILLISECONDS); + baseEnvironment.put(environmentKey, timeout.toString()); + } catch (final IllegalArgumentException iae) { + throw new ProviderCreationException(String.format("The %s '%s' is not a valid time duration", configurationProperty, rawTimeout)); + } + } + } + + @Override + public final AuthenticationResponse authenticate(final LoginCredentials credentials) throws InvalidLoginCredentialsException, IdentityAccessException { + if (provider == null) { + throw new IdentityAccessException("The LDAP authentication provider is not initialized."); + } + + try { + // perform the authentication + final UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword()); + final Authentication authentication = provider.authenticate(token); + + // 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(), expiration, issuer); + } else { + return new AuthenticationResponse(authentication.getName(), credentials.getUsername(), expiration, issuer); + } + } 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); + } + } + + @Override + public final void preDestruction() throws ProviderDestructionException { + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/java/org/apache/nifi/ldap/ReferralStrategy.java ---------------------------------------------------------------------- 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 0000000..f4c5131 --- /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; + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider new file mode 100644 index 0000000..b5ca1fe --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/nifi-ldap-iaa-providers/src/main/resources/META-INF/services/org.apache.nifi.authentication.LoginIdentityProvider @@ -0,0 +1,15 @@ +# 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. +org.apache.nifi.ldap.LdapProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/pom.xml b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/pom.xml new file mode 100644 index 0000000..e038c2c --- /dev/null +++ b/nifi-nar-bundles/nifi-ldap-iaa-providers-bundle/pom.xml @@ -0,0 +1,38 @@ + + + + 4.0.0 + + org.apache.nifi + nifi-nar-bundles + 0.3.1-SNAPSHOT + + nifi-ldap-iaa-providers-bundle + pom + + nifi-ldap-iaa-providers + nifi-ldap-iaa-providers-nar + + + + + org.apache.nifi + nifi-ldap-iaa-providers + 0.3.1-SNAPSHOT + + + + \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/nifi-nar-bundles/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/pom.xml b/nifi-nar-bundles/pom.xml index 4c0925f..a9c7728 100644 --- a/nifi-nar-bundles/pom.xml +++ b/nifi-nar-bundles/pom.xml @@ -48,6 +48,7 @@ nifi-avro-bundle nifi-couchbase-bundle nifi-azure-bundle + nifi-ldap-iaa-providers-bundle http://git-wip-us.apache.org/repos/asf/nifi/blob/aaf14c45/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 0708812..249f01c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,14 +1,14 @@ +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. --> 4.0.0 @@ -91,7 +91,7 @@ 9.2.11.v20150529 4.10.4 4.1.6.RELEASE - 3.2.7.RELEASE + 4.0.3.RELEASE 1.19 2.6.2 12.0.1 @@ -290,8 +290,8 @@ 2.2.1 + lgpl licensed | We also don't use the JDBC related features of quartz for + which the dependency would matter --> c3p0 c3p0 @@ -361,7 +361,7 @@ ${spring.version} + section --> commons-logging commons-logging @@ -504,6 +504,29 @@ + org.springframework.security + spring-security-ldap + ${spring.security.version} + + + org.springframework + spring-core + + + org.springframework + spring-beans + + + org.springframework + spring-context + + + org.springframework + spring-tx + + + + org.aspectj aspectjweaver 1.8.5 @@ -977,6 +1000,12 @@ org.apache.nifi + nifi-ldap-iaa-providers-nar + 0.3.1-SNAPSHOT + nar + + + org.apache.nifi nifi-properties 0.4.0-SNAPSHOT @@ -1262,7 +1291,7 @@ + brace --> @@ -1352,11 +1381,11 @@ + for contributions and for the release process. While it would be nice to + run always these plugins can considerably slow the build and have proven + to create unstable builds in our multi-module project and when building using + multiple threads. The stability issues seen with Checkstyle in multi-module + builds include false-positives and false negatives. --> contrib-check