diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java index d381f740a8..4a7e5d8c57 100644 --- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java @@ -179,8 +179,10 @@ public abstract class NiFiProperties { // kerberos properties public static final String KERBEROS_KRB5_FILE = "nifi.kerberos.krb5.file"; public static final String KERBEROS_SERVICE_PRINCIPAL = "nifi.kerberos.service.principal"; - public static final String KERBEROS_KEYTAB_LOCATION = "nifi.kerberos.keytab.location"; - public static final String KERBEROS_AUTHENTICATION_EXPIRATION = "nifi.kerberos.authentication.expiration"; + public static final String KERBEROS_SERVICE_KEYTAB_LOCATION = "nifi.kerberos.service.keytab.location"; + public static final String KERBEROS_SPNEGO_PRINCIPAL = "nifi.kerberos.spnego.principal"; + public static final String KERBEROS_SPNEGO_KEYTAB_LOCATION = "nifi.kerberos.spnego.keytab.location"; + public static final String KERBEROS_AUTHENTICATION_EXPIRATION = "nifi.kerberos.spnego.authentication.expiration"; // state management public static final String STATE_MANAGEMENT_CONFIG_FILE = "nifi.state.management.configuration.file"; @@ -717,8 +719,26 @@ public abstract class NiFiProperties { } } - public String getKerberosKeytabLocation() { - final String keytabLocation = getProperty(KERBEROS_KEYTAB_LOCATION); + public String getKerberosServiceKeytabLocation() { + final String keytabLocation = getProperty(KERBEROS_SERVICE_KEYTAB_LOCATION); + if (!StringUtils.isBlank(keytabLocation)) { + return keytabLocation.trim(); + } else { + return null; + } + } + + public String getKerberosSpnegoPrincipal() { + final String spengoPrincipal = getProperty(KERBEROS_SPNEGO_PRINCIPAL); + if (!StringUtils.isBlank(spengoPrincipal)) { + return spengoPrincipal.trim(); + } else { + return null; + } + } + + public String getKerberosSpnegoKeytabLocation() { + final String keytabLocation = getProperty(KERBEROS_SPNEGO_KEYTAB_LOCATION); if (!StringUtils.isBlank(keytabLocation)) { return keytabLocation.trim(); } else { @@ -741,8 +761,8 @@ public abstract class NiFiProperties { * * @return true if Kerberos service support is enabled */ - public boolean isKerberosServiceSupportEnabled() { - return !StringUtils.isBlank(getKerberosServicePrincipal()) && !StringUtils.isBlank(getKerberosKeytabLocation()); + public boolean isKerberosSpnegoSupportEnabled() { + return !StringUtils.isBlank(getKerberosSpnegoPrincipal()) && !StringUtils.isBlank(getKerberosSpnegoKeytabLocation()); } /** @@ -756,7 +776,7 @@ public abstract class NiFiProperties { * API */ public boolean isClientAuthRequiredForRestApi() { - return StringUtils.isBlank(getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER)) && !isKerberosServiceSupportEnabled(); + return StringUtils.isBlank(getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER)) && !isKerberosSpnegoSupportEnabled(); } public InetSocketAddress getNodeApiAddress() { diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc index b0a96de985..65e98456ec 100644 --- a/nifi-docs/src/main/asciidoc/administration-guide.adoc +++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc @@ -1903,15 +1903,19 @@ that is specified. |==== |*Property*|*Description* -|nifi.kerberos.krb5.file*|The location of the krb5 file, if used. It is blank by default. Note that this property is not used to authenticate NiFi users. - Rather, it is made available for extension points, such as Hadoop-based Processors, to use. At this time, only a single krb5 file is allowed to - be specified per NiFi instance, so this property is configured here rather than in individual Processors. +|nifi.kerberos.krb5.file*|The location of the krb5 file, if used. It is blank by default. At this time, only a single krb5 file is allowed to + be specified per NiFi instance, so this property is configured here to support SPNEGO and service principles rather than in individual Processors. + If necessary the krb5 file can support multiple realms. Example: `/etc/krb5.conf` -|nifi.kerberos.service.principal*|The name of the NiFi Kerberos service principal, if used. It is blank by default. Note that this property is used to authenticate NiFi users. +|nifi.kerberos.service.principal*|The name of the NiFi Kerberos service principal, if used. It is blank by default. Note that this property is for NiFi to authenticate as a client other systems. + Example: `nifi/nifi.example.com` or `nifi/nifi.example.com@EXAMPLE.COM` +|nifi.kerberos.service.keytab.location*|The file path of the NiFi Kerberos keytab, if used. It is blank by default. Note that this property is for NiFi to authenticate as a client other systems. + Example: `/etc/nifi.keytab` +|nifi.kerberos.spnego.principal*|The name of the NiFi Kerberos service principal, if used. It is blank by default. Note that this property is used to authenticate NiFi users. Example: `HTTP/nifi.example.com` or `HTTP/nifi.example.com@EXAMPLE.COM` -|nifi.kerberos.keytab.location*|The file path of the NiFi Kerberos keytab, if used. It is blank by default. Note that this property is used to authenticate NiFi users. +|nifi.kerberos.spnego.keytab.location*|The file path of the NiFi Kerberos keytab, if used. It is blank by default. Note that this property is used to authenticate NiFi users. Example: `/etc/http-nifi.keytab` -|nifi.kerberos.authentication.expiration*|The expiration duration of a successful Kerberos user authentication, if used. It is 12 hours by default. +|nifi.kerberos.spengo.authentication.expiration*|The expiration duration of a successful Kerberos user authentication, if used. It is 12 hours by default. Example: `12 hours` |==== diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml index fff546b87e..e367e2af14 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml @@ -161,8 +161,10 @@ - - 12 hours + + + + 12 hours diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties index a65b26570a..485b60e494 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties @@ -179,9 +179,15 @@ nifi.zookeeper.root.node=${nifi.zookeeper.root.node} # kerberos # nifi.kerberos.krb5.file=${nifi.kerberos.krb5.file} + +# kerberos service principle # nifi.kerberos.service.principal=${nifi.kerberos.service.principal} -nifi.kerberos.keytab.location=${nifi.kerberos.keytab.location} -nifi.kerberos.authentication.expiration=${nifi.kerberos.authentication.expiration} +nifi.kerberos.service.keytab.location=${nifi.kerberos.service.keytab.location} + +# kerberos spnego principle # +nifi.kerberos.spnego.principal=${nifi.kerberos.spnego.principal} +nifi.kerberos.spnego.keytab.location=${nifi.kerberos.spnego.keytab.location} +nifi.kerberos.spnego.authentication.expiration=${nifi.kerberos.spnego.authentication.expiration} # external properties files for variable registry # supports a comma delimited list of file locations diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java index 6ced1c09a3..5c108a49ac 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java @@ -345,7 +345,7 @@ public class AccessResource extends ApplicationResource { } // If Kerberos Service Principal and keytab location not configured, throws exception - if (!properties.isKerberosServiceSupportEnabled() || kerberosService == null) { + if (!properties.isKerberosSpnegoSupportEnabled() || kerberosService == null) { throw new IllegalStateException("Kerberos ticket login not supported by this NiFi."); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/site-to-site/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/site-to-site/nifi.properties index 3d7d0e8b3f..4800770728 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/site-to-site/nifi.properties +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/resources/site-to-site/nifi.properties @@ -170,5 +170,7 @@ nifi.zookeeper.root.node=${nifi.zookeeper.root.node} # kerberos # nifi.kerberos.krb5.file=${nifi.kerberos.krb5.file} nifi.kerberos.service.principal=${nifi.kerberos.service.principal} -nifi.kerberos.keytab.location=${nifi.kerberos.keytab.location} -nifi.kerberos.authentication.expiration=${nifi.kerberos.authentication.expiration} \ No newline at end of file +nifi.kerberos.service.keytab.location=${nifi.kerberos.service.keytab.location} +nifi.kerberos.spnego.principal=${nifi.kerberos.spnego.principal} +nifi.kerberos.spnego.keytab.location=${nifi.kerberos.spnego.keytab.location} +nifi.kerberos.spnego.authentication.expiration=${nifi.kerberos.spnego.authentication.expiration} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/KerberosServiceFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/KerberosServiceFactoryBean.java index bbe15d120e..3ea7f5df50 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/KerberosServiceFactoryBean.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/KerberosServiceFactoryBean.java @@ -23,8 +23,11 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.core.io.FileSystemResource; import org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider; import org.springframework.security.kerberos.authentication.KerberosTicketValidator; +import org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig; import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator; +import java.io.File; + public class KerberosServiceFactoryBean implements FactoryBean { private KerberosService kerberosService = null; @@ -32,7 +35,14 @@ public class KerberosServiceFactoryBean implements FactoryBean @Override public KerberosService getObject() throws Exception { - if (kerberosService == null && properties.isKerberosServiceSupportEnabled()) { + if (kerberosService == null && properties.isKerberosSpnegoSupportEnabled()) { + final File krb5ConfigFile = properties.getKerberosConfigurationFile(); + if (krb5ConfigFile != null) { + final GlobalSunJaasKerberosConfig krb5Config = new GlobalSunJaasKerberosConfig(); + krb5Config.setKrbConfLocation(krb5ConfigFile.getAbsolutePath()); + krb5Config.afterPropertiesSet(); + } + kerberosService = new KerberosService(); kerberosService.setKerberosServiceAuthenticationProvider(createKerberosServiceAuthenticationProvider()); } @@ -68,8 +78,8 @@ public class KerberosServiceFactoryBean implements FactoryBean private KerberosTicketValidator createTicketValidator() throws Exception { SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator(); - ticketValidator.setServicePrincipal(properties.getKerberosServicePrincipal()); - ticketValidator.setKeyTabLocation(new FileSystemResource(properties.getKerberosKeytabLocation())); + ticketValidator.setServicePrincipal(properties.getKerberosSpnegoPrincipal()); + ticketValidator.setKeyTabLocation(new FileSystemResource(properties.getKerberosSpnegoKeytabLocation())); ticketValidator.afterPropertiesSet(); return ticketValidator; } diff --git a/nifi-nar-bundles/nifi-kerberos-iaa-providers-bundle/nifi-kerberos-iaa-providers/src/main/java/org/apache/nifi/kerberos/KerberosProvider.java b/nifi-nar-bundles/nifi-kerberos-iaa-providers-bundle/nifi-kerberos-iaa-providers/src/main/java/org/apache/nifi/kerberos/KerberosProvider.java index f9856020af..1b35514de1 100644 --- a/nifi-nar-bundles/nifi-kerberos-iaa-providers-bundle/nifi-kerberos-iaa-providers/src/main/java/org/apache/nifi/kerberos/KerberosProvider.java +++ b/nifi-nar-bundles/nifi-kerberos-iaa-providers-bundle/nifi-kerberos-iaa-providers/src/main/java/org/apache/nifi/kerberos/KerberosProvider.java @@ -33,6 +33,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.kerberos.authentication.KerberosAuthenticationProvider; +import org.springframework.security.kerberos.authentication.sun.GlobalSunJaasKerberosConfig; import org.springframework.security.kerberos.authentication.sun.SunJaasKerberosClient; import java.util.concurrent.TimeUnit; @@ -66,6 +67,17 @@ public class KerberosProvider implements LoginIdentityProvider { throw new ProviderCreationException(String.format("The Expiration Duration '%s' is not a valid time duration", rawExpiration)); } + try { + final String krb5ConfigFile = configurationContext.getProperty("Kerberos Config File"); + if (StringUtils.isNotEmpty(krb5ConfigFile)) { + final GlobalSunJaasKerberosConfig krb5Config = new GlobalSunJaasKerberosConfig(); + krb5Config.setKrbConfLocation(krb5ConfigFile); + krb5Config.afterPropertiesSet(); + } + } catch (final Exception e) { + throw new ProviderCreationException(e.getMessage(), e); + } + provider = new KerberosAuthenticationProvider(); SunJaasKerberosClient client = new SunJaasKerberosClient(); client.setDebug(true); diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java index ab31fa3f29..a86423cc82 100644 --- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java +++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java @@ -102,7 +102,7 @@ public class RangerNiFiAuthorizer implements Authorizer { // login with the nifi principal and keytab, RangerAdminRESTClient will use Ranger's MiscUtil which // will grab UserGroupInformation.getLoginUser() and call ugi.checkTGTAndReloginFromKeytab(); final String nifiPrincipal = nifiProperties.getKerberosServicePrincipal(); - final String nifiKeytab = nifiProperties.getKerberosKeytabLocation(); + final String nifiKeytab = nifiProperties.getKerberosServiceKeytabLocation(); if (StringUtils.isBlank(nifiPrincipal) || StringUtils.isBlank(nifiKeytab)) { throw new AuthorizerCreationException("Principal and Keytab must be provided when Kerberos is enabled"); diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/TestRangerNiFiAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/TestRangerNiFiAuthorizer.java index af5012503b..1bfa1b3fcf 100644 --- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/TestRangerNiFiAuthorizer.java +++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/TestRangerNiFiAuthorizer.java @@ -149,7 +149,7 @@ public class TestRangerNiFiAuthorizer { .thenReturn(new MockPropertyValue("true")); nifiProperties = Mockito.mock(NiFiProperties.class); - when(nifiProperties.getKerberosKeytabLocation()).thenReturn(""); + when(nifiProperties.getKerberosServiceKeytabLocation()).thenReturn(""); authorizer = new MockRangerNiFiAuthorizer(rangerBasePlugin); authorizer.setNiFiProperties(nifiProperties); @@ -169,7 +169,7 @@ public class TestRangerNiFiAuthorizer { .thenReturn(new MockPropertyValue("true")); nifiProperties = Mockito.mock(NiFiProperties.class); - when(nifiProperties.getKerberosKeytabLocation()).thenReturn(""); + when(nifiProperties.getKerberosServiceKeytabLocation()).thenReturn(""); when(nifiProperties.getKerberosServicePrincipal()).thenReturn(""); authorizer = new MockRangerNiFiAuthorizer(rangerBasePlugin); @@ -203,7 +203,7 @@ public class TestRangerNiFiAuthorizer { .thenReturn(new MockPropertyValue("true")); nifiProperties = Mockito.mock(NiFiProperties.class); - when(nifiProperties.getKerberosKeytabLocation()).thenReturn("test"); + when(nifiProperties.getKerberosServiceKeytabLocation()).thenReturn("test"); when(nifiProperties.getKerberosServicePrincipal()).thenReturn("test"); authorizer = new MockRangerNiFiAuthorizer(rangerBasePlugin); diff --git a/nifi-toolkit/nifi-toolkit-tls/src/test/resources/localhost/nifi.properties b/nifi-toolkit/nifi-toolkit-tls/src/test/resources/localhost/nifi.properties index 41b091c8ab..deda7f9abf 100644 --- a/nifi-toolkit/nifi-toolkit-tls/src/test/resources/localhost/nifi.properties +++ b/nifi-toolkit/nifi-toolkit-tls/src/test/resources/localhost/nifi.properties @@ -173,5 +173,8 @@ nifi.zookeeper.root.node=/nifi # kerberos # nifi.kerberos.krb5.file= nifi.kerberos.service.principal= -nifi.kerberos.keytab.location= -nifi.kerberos.authentication.expiration=12 hours +nifi.kerberos.service.keytab.location= + +nifi.kerberos.spnego.principal= +nifi.kerberos.spnego.keytab.location= +nifi.kerberos.spnego.authentication.expiration=12 hours \ No newline at end of file