You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@nifi.apache.org by GitBox <gi...@apache.org> on 2021/04/06 05:18:20 UTC

[GitHub] [nifi] timeabarna opened a new pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

timeabarna opened a new pull request #4973:
URL: https://github.com/apache/nifi/pull/4973


   Add Kerberos support to Accumulo processors
   
   https://issues.apache.org/jira/browse/NIFI-8373
   
   #### Description of PR
   
   Add Kerberos support to Accumulo processors
   
   In order to streamline the review of the contribution we ask you
   to ensure the following steps have been taken:
   
   ### For all changes:
   - [ ] Is there a JIRA ticket associated with this PR? Is it referenced 
        in the commit message?
   
   - [ ] Does your PR title start with **NIFI-XXXX** where XXXX is the JIRA number you are trying to resolve? Pay particular attention to the hyphen "-" character.
   
   - [ ] Has your PR been rebased against the latest commit within the target branch (typically `main`)?
   
   - [ ] Is your initial contribution a single, squashed commit? _Additional commits in response to PR reviewer feedback should be made on this branch and pushed to allow change tracking. Do not `squash` or use `--force` when pushing to allow for clean monitoring of changes._
   
   ### For code changes:
   - [ ] Have you ensured that the full suite of tests is executed via `mvn -Pcontrib-check clean install` at the root `nifi` folder?
   - [ ] Have you written or updated unit tests to verify your changes?
   - [ ] Have you verified that the full build is successful on JDK 8?
   - [ ] Have you verified that the full build is successful on JDK 11?
   - [ ] If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under [ASF 2.0](http://www.apache.org/legal/resolved.html#category-a)? 
   - [ ] If applicable, have you updated the `LICENSE` file, including the main `LICENSE` file under `nifi-assembly`?
   - [ ] If applicable, have you updated the `NOTICE` file, including the main `NOTICE` file found under `nifi-assembly`?
   - [ ] If adding new Properties, have you added `.displayName` in addition to .name (programmatic access) for each of the new properties?
   
   ### For documentation related changes:
   - [ ] Have you ensured that format looks appropriate for the output in which it is rendered?
   
   ### Note:
   Please ensure that once the PR is submitted, you check GitHub Actions CI for build issues and submit an update to your PR as soon as possible.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-836553628


   @phrocker  All the planned changes are up, you can test it. Thanks in advance for your help.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] joshelser commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
joshelser commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r607955331



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");
+                clientConf.setProperty("sasl.qop", context.getProperty(ACCUMULO_SASL_QOP).getValue());
+
+                //Client uses the currently logged in user's security context, so need to login first.
+                Configuration conf = new Configuration();
+                conf.set("hadoop.security.authentication", "kerberos");
+                UserGroupInformation.setConfiguration(conf);
+                UserGroupInformation.loginUserFromKeytab(principal, kerberosService.getKeytab());

Review comment:
       If memory serves, in other processors/services, Nifi calls `loginUserFromKeytabAndReturnUGI` instead.
   
   `loginUserFromKeytab` does a nasty thing where it sets a static variable inside of `UserGroupInformation` and considers that the "current user". In a multi-threaded application like Nifi, the unintended consequences of API like this can be pretty drastic.
   
   I'd suggest switching this to be:
   ```
   UserGroupInformation clientUgi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, kerberosServices.getKeytab());
   clientUgi.doAs(() -> {
     token = new KerberosToken();
     client = Accumulo.newClient().from(clientConf).as(principal, token).build();
   });
   ```
   As a word of warning, you will likely also have to wrap interactions wtih the `AccumuloClient` you created with its own `clientUgi.doAs()`.

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");

Review comment:
       If you are setting these, you probably also want to set `instance.rpc.sasl.enabled=true`

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");
+                clientConf.setProperty("sasl.qop", context.getProperty(ACCUMULO_SASL_QOP).getValue());
+
+                //Client uses the currently logged in user's security context, so need to login first.
+                Configuration conf = new Configuration();
+                conf.set("hadoop.security.authentication", "kerberos");
+                UserGroupInformation.setConfiguration(conf);
+                UserGroupInformation.loginUserFromKeytab(principal, kerberosService.getKeytab());
 
-        this.client = Accumulo.newClient().to(instanceName,zookeepers).as(accumuloUser,token).build();
+                token = new KerberosToken();
+
+                this.client = Accumulo.newClient().from(clientConf).as(principal, token).build();
+                break;
+            default:
+                token = null;
+        }
 
         if (null == token){
             throw new InitializationException("Feature not implemented");

Review comment:
       Since you're falling down into this branch, you probably want to update the error message to be a bit more meaningful.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] tpalfy commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
tpalfy commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-845907808


   LGTM+1
   
   Merged to main.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] phrocker commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
phrocker commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-824166125


   @pvillard31 I will try and find some time to get this tested. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] asfgit closed pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
asfgit closed pull request #4973:
URL: https://github.com/apache/nifi/pull/4973


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] phrocker commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
phrocker commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-836519496


   @timeabarna  I saw some changes within the last few days. Is this okay to test or are there additional changes coming down the pipline? I am hoping to find some additional time to test this week -- It seemed okay when I tried it the week before last but wanted to try to find some time to test with the additional changes. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] phrocker edited a comment on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
phrocker edited a comment on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-836519496


   @timeabarna  I saw some changes within the last few days. Is this okay to test or are there additional changes coming down the pipeline? I am hoping to find some additional time to test this week -- It seemed okay when I tried it the week before last but wanted to try to find some time to test with the additional changes. 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] joshelser commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
joshelser commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r616818175



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");

Review comment:
       Looks like you're right. I didn't remember that they had separated client and server configuration properties. So, by virtue of passing the KerberosToken, you wouldn't need to do anything else.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] bbende commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r616660664



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +61,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
-            .name("ZooKeeper Quorum")
+            .name("accumulo-zooKeeper-quorum")

Review comment:
       We can't change the name of existing properties, that is the reason for displayName which can be used to change what the user sees in the UI. The regular name is a key that is used in the flow configuration, so if we change it then anyone using this component will have to reconfigure it when they upgrade to the release with this change because their will flow will reference a now unknown property name "ZooKeeper Quorum".




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] pvillard31 commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
pvillard31 commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-823041147


   @joshelser @bbende - does it look good to you?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r617205303



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +61,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
-            .name("ZooKeeper Quorum")
+            .name("accumulo-zooKeeper-quorum")

Review comment:
       Thanks @bbende restored the name to original




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] bbende commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
bbende commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-823257230


   @pvillard31 I don't really see any issues, but I don't currently have time to try it out


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] tpalfy commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
tpalfy commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r620407997



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +61,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
             .name("ZooKeeper Quorum")
+            .displayName("ZooKeeper Quorum")
             .description("Comma-separated list of ZooKeeper hosts for Accumulo.")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
     protected static final PropertyDescriptor INSTANCE_NAME = new PropertyDescriptor.Builder()
-            .name("Instance Name")
+            .name("accumulo-instance-name")
+            .displayName("Instance Name")
             .description("Instance name of the Accumulo cluster")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
+    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
+            .name("accumulo-authentication-type")
+            .displayName("Authentication Type")
+            .description("Authentication Type")
+            .allowableValues(AuthenticationType.values())
+            .defaultValue(AuthenticationType.PASSWORD.toString())
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
 
     protected static final PropertyDescriptor ACCUMULO_USER = new PropertyDescriptor.Builder()
-            .name("Accumulo User")
+            .name("accumulo-user")
+            .displayName("Accumulo User")
             .description("Connecting user for Accumulo")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
     protected static final PropertyDescriptor ACCUMULO_PASSWORD = new PropertyDescriptor.Builder()
-            .name("Accumulo Password")
-            .description("Connecting user's password when using the PASSWORD Authentication type")
+            .name("accumulo-password")
+            .displayName("Accumulo Password")
+            .description("Connecting user's password")
             .sensitive(true)
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
-    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
-            .name("Authentication Type")
-            .description("Authentication Type")
-            .allowableValues(AuthenticationType.values())
-            .defaultValue(AuthenticationType.PASSWORD.toString())
+    protected static final PropertyDescriptor KERBEROS_CREDENTIALS_SERVICE = new PropertyDescriptor.Builder()
+            .name("kerberos-credentials-service")
+            .displayName("Kerberos Credentials Service")
+            .description("Specifies the Kerberos Credentials Controller Service that should be used for principal + keytab Kerberos authentication")
+            .identifiesControllerService(KerberosCredentialsService.class)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS.toString())
+            .build();
+
+    protected static final PropertyDescriptor ACCUMULO_PRINCIPAL = new PropertyDescriptor.Builder()
+            .name("accumulo-principal")
+            .displayName("Accumulo Principal")
+            .description("Connecting principal for Accumulo")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS.toString())
             .build();
 
+    protected static final PropertyDescriptor ACCUMULO_PASSWORD_FOR_KERBEROS = new PropertyDescriptor.Builder()

Review comment:
       ```suggestion
       protected static final PropertyDescriptor KERBEROS_PASSWORD = new PropertyDescriptor.Builder()
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +205,106 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Password and Kerberos Credential Service should not be filled out at the same time").build());

Review comment:
       ```suggestion
                               .explanation("Kerberos Password and Kerberos Credential Service should not be filled out at the same time").build());
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +61,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
             .name("ZooKeeper Quorum")
+            .displayName("ZooKeeper Quorum")
             .description("Comma-separated list of ZooKeeper hosts for Accumulo.")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
     protected static final PropertyDescriptor INSTANCE_NAME = new PropertyDescriptor.Builder()
-            .name("Instance Name")
+            .name("accumulo-instance-name")
+            .displayName("Instance Name")
             .description("Instance name of the Accumulo cluster")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
+    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
+            .name("accumulo-authentication-type")
+            .displayName("Authentication Type")
+            .description("Authentication Type")
+            .allowableValues(AuthenticationType.values())
+            .defaultValue(AuthenticationType.PASSWORD.toString())
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
 
     protected static final PropertyDescriptor ACCUMULO_USER = new PropertyDescriptor.Builder()
-            .name("Accumulo User")
+            .name("accumulo-user")
+            .displayName("Accumulo User")
             .description("Connecting user for Accumulo")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
     protected static final PropertyDescriptor ACCUMULO_PASSWORD = new PropertyDescriptor.Builder()
-            .name("Accumulo Password")
-            .description("Connecting user's password when using the PASSWORD Authentication type")
+            .name("accumulo-password")
+            .displayName("Accumulo Password")
+            .description("Connecting user's password")
             .sensitive(true)
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
-    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
-            .name("Authentication Type")
-            .description("Authentication Type")
-            .allowableValues(AuthenticationType.values())
-            .defaultValue(AuthenticationType.PASSWORD.toString())
+    protected static final PropertyDescriptor KERBEROS_CREDENTIALS_SERVICE = new PropertyDescriptor.Builder()
+            .name("kerberos-credentials-service")
+            .displayName("Kerberos Credentials Service")
+            .description("Specifies the Kerberos Credentials Controller Service that should be used for principal + keytab Kerberos authentication")
+            .identifiesControllerService(KerberosCredentialsService.class)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS.toString())
+            .build();
+
+    protected static final PropertyDescriptor ACCUMULO_PRINCIPAL = new PropertyDescriptor.Builder()

Review comment:
       ```suggestion
       protected static final PropertyDescriptor KERBEROS_PRINCIPAL = new PropertyDescriptor.Builder()
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +61,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
             .name("ZooKeeper Quorum")
+            .displayName("ZooKeeper Quorum")
             .description("Comma-separated list of ZooKeeper hosts for Accumulo.")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
     protected static final PropertyDescriptor INSTANCE_NAME = new PropertyDescriptor.Builder()
-            .name("Instance Name")
+            .name("accumulo-instance-name")

Review comment:
       Changing the name can lead to compatibility issues. 

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +205,106 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either password or Kerberos Credential Service must be set").build());

Review comment:
       ```suggestion
                               .explanation("Either Kerberos Password or Kerberos Credential Service must be set").build());
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -107,34 +161,35 @@
      */
     private List<PropertyDescriptor> properties;
 
+    private AuthenticationType authType;

Review comment:
       No need to extract as field.

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +205,106 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());

Review comment:
       ```suggestion
                                       .explanation("Kerberos Password must be supplied for the Password Authentication type").build());
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +205,106 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Password and Kerberos Credential Service should not be filled out at the same time").build());
+                } else if (validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet() && !validationContext.getProperty(ACCUMULO_PRINCIPAL).isSet()) {
+                    problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PRINCIPAL.getName())
+                            .explanation("Kerberos principal must be supplied when principal + password Kerberos authentication is used").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PRINCIPAL).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PRINCIPAL.getName())
+                            .explanation("Principal should not be filled out when principal + keytab Kerberos authentication is used").build());

Review comment:
       ```suggestion
                               .explanation("Kerberos Principal (for password) should not be filled out when principal + keytab Kerberos authentication is used").build());
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +205,106 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Password and Kerberos Credential Service should not be filled out at the same time").build());
+                } else if (validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet() && !validationContext.getProperty(ACCUMULO_PRINCIPAL).isSet()) {
+                    problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PRINCIPAL.getName())
+                            .explanation("Kerberos principal must be supplied when principal + password Kerberos authentication is used").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PRINCIPAL).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PRINCIPAL.getName())
+                            .explanation("Principal should not be filled out when principal + keytab Kerberos authentication is used").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
     public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        final AtomicReference<AuthenticationToken> token = new AtomicReference<>();
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token.set(new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue()));
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser, token.get()).build();
+                break;
+            case KERBEROS:
+                final String principal = kerberosService == null ? context.getProperty(ACCUMULO_PRINCIPAL).getValue() : kerberosService.getPrincipal();
+                final AtomicReference<KerberosUser> kerberosUser = new AtomicReference<>();

Review comment:
       This doesn't need to be AtomicReference.

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +205,106 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Password and Kerberos Credential Service should not be filled out at the same time").build());
+                } else if (validationContext.getProperty(ACCUMULO_PASSWORD_FOR_KERBEROS).isSet() && !validationContext.getProperty(ACCUMULO_PRINCIPAL).isSet()) {
+                    problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PRINCIPAL.getName())
+                            .explanation("Kerberos principal must be supplied when principal + password Kerberos authentication is used").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(ACCUMULO_PRINCIPAL).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PRINCIPAL.getName())
+                            .explanation("Principal should not be filled out when principal + keytab Kerberos authentication is used").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
     public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        final AtomicReference<AuthenticationToken> token = new AtomicReference<>();

Review comment:
       This doesn't need to be AtomicReference.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r617204260



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");

Review comment:
       Thanks @joshelser




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-814974273


   @joshelser @bbende Josh and Bryan thank you very much for your help, PR has been updated


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r608365626



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");

Review comment:
       @joshelser Thanks Josh for your recommendation. My understanding is that instance.rpc.sasl.enabled is an Accumulo server property, would this be recognised by the client? I could not find it as a valid property for client configuration in Accumulo documentation ( https://accumulo.apache.org/docs/2.x/configuration/client-properties ).




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] tpalfy commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
tpalfy commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r623877866



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +194,110 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(KERBEROS_PASSWORD).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either Kerberos Password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(KERBEROS_PASSWORD).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Kerberos Password and Kerberos Credential Service should not be filled out at the same time").build());
+                } else if (validationContext.getProperty(KERBEROS_PASSWORD).isSet() && !validationContext.getProperty(KERBEROS_PRINCIPAL).isSet()) {
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_PRINCIPAL.getName())
+                            .explanation("Kerberos Principal must be supplied when principal + password Kerberos authentication is used").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(KERBEROS_PRINCIPAL).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_PRINCIPAL.getName())
+                            .explanation("Kerberos Principal (for password) should not be filled out when principal + keytab Kerberos authentication is used").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
     public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        final AuthenticationType authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                final AuthenticationToken token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser, token).build();
+                break;
+            case KERBEROS:
+                final String principal;
+
+                if (kerberosService == null) {
+                    principal = context.getProperty(KERBEROS_PRINCIPAL).getValue();
+                    this.kerberosUser = new KerberosPasswordUser(principal, context.getProperty(KERBEROS_PASSWORD).getValue());
+                } else {
+                    principal = kerberosService.getPrincipal();
+                    this.kerberosUser = new KerberosKeytabUser(principal, kerberosService.getKeytab());
+                }
 
-        this.client = Accumulo.newClient().to(instanceName,zookeepers).as(accumuloUser,token).build();
+                clientConf.setProperty("sasl.enabled", "true");
+                clientConf.setProperty("sasl.qop", context.getProperty(ACCUMULO_SASL_QOP).getValue());
 
-        if (null == token){
-            throw new InitializationException("Feature not implemented");
-        }
+                //Client uses the currently logged in user's security context, so need to login first.
+                Configuration conf = new Configuration();
+                conf.set("hadoop.security.authentication", "kerberos");
+                UserGroupInformation.setConfiguration(conf);
+                final UserGroupInformation clientUgi = SecurityUtil.getUgiForKerberosUser(conf, kerberosUser);
 
+                this.client = clientUgi.doAs((PrivilegedExceptionAction<AccumuloClient>) () ->
+                        Accumulo.newClient().from(clientConf).as(principal, new KerberosToken()).build());
+                break;
+            default:
+                throw new InitializationException("Not supported authentication type.");
+        }
     }
 
     @Override
-    public AccumuloClient getClient(){
+    public AccumuloClient getClient() {
         return client;
     }
 
+    @Override
+    public void renewTgtIfNecessary() {
+        if (kerberosUser != null) {

Review comment:
       It's possible for `kerberosUser` to be _not_ null even if the 'Authentication Type' is set to 'PASSWORD' after it was set to 'KERBEROS' before.
   
   At best we do unintentional TGT renewal, at worst this can even lead to a false failure if the previously set kerberos credentials are invalid.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-845978458


   @phrocker No worries. Thank you very much for your help. Your feedback and time are much appreciated.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] timeabarna commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
timeabarna commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r608365626



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");

Review comment:
       @joshelser Thanks Josh for your recommendation. My understanding is that instance.rpc.sasl.enabled is an Accumulo server property, would this be recognised by the client? I could not find it as a valid property for client configuration in Accumulo documentation ( https://accumulo..apache.org/docs/2.x/configuration/client-properties ).




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] tpalfy commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
tpalfy commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r621158879



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +60,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
             .name("ZooKeeper Quorum")
+            .displayName("ZooKeeper Quorum")
             .description("Comma-separated list of ZooKeeper hosts for Accumulo.")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
     protected static final PropertyDescriptor INSTANCE_NAME = new PropertyDescriptor.Builder()
             .name("Instance Name")
+            .displayName("Instance Name")
             .description("Instance name of the Accumulo cluster")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
+    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
+            .name("accumulo-authentication-type")
+            .displayName("Authentication Type")
+            .description("Authentication Type")
+            .allowableValues(AuthenticationType.values())
+            .defaultValue(AuthenticationType.PASSWORD.toString())
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
 
     protected static final PropertyDescriptor ACCUMULO_USER = new PropertyDescriptor.Builder()
             .name("Accumulo User")
+            .displayName("Accumulo User")
             .description("Connecting user for Accumulo")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
     protected static final PropertyDescriptor ACCUMULO_PASSWORD = new PropertyDescriptor.Builder()
             .name("Accumulo Password")
-            .description("Connecting user's password when using the PASSWORD Authentication type")
+            .displayName("Accumulo Password")
+            .description("Connecting user's password")
             .sensitive(true)
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
-    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
-            .name("Authentication Type")
-            .description("Authentication Type")
-            .allowableValues(AuthenticationType.values())
-            .defaultValue(AuthenticationType.PASSWORD.toString())
+    protected static final PropertyDescriptor KERBEROS_CREDENTIALS_SERVICE = new PropertyDescriptor.Builder()
+            .name("kerberos-credentials-service")
+            .displayName("Kerberos Credentials Service")
+            .description("Specifies the Kerberos Credentials Controller Service that should be used for principal + keytab Kerberos authentication")
+            .identifiesControllerService(KerberosCredentialsService.class)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS.toString())
+            .build();
+
+    protected static final PropertyDescriptor KERBEROS_PRINCIPAL = new PropertyDescriptor.Builder()
+            .name("accumulo-kerberos-principal")

Review comment:
       ```suggestion
               .name("kerberos-principal")
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +204,108 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(KERBEROS_PASSWORD).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either Kerberos Password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(KERBEROS_PASSWORD).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Kerberos Password and Kerberos Credential Service should not be filled out at the same time").build());
+                } else if (validationContext.getProperty(KERBEROS_PASSWORD).isSet() && !validationContext.getProperty(KERBEROS_PRINCIPAL).isSet()) {
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_PRINCIPAL.getName())
+                            .explanation("Kerberos Principal must be supplied when principal + password Kerberos authentication is used").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(KERBEROS_PRINCIPAL).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_PRINCIPAL.getName())
+                            .explanation("Kerberos Principal (for password) should not be filled out when principal + keytab Kerberos authentication is used").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
     public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        final AuthenticationType authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                final AuthenticationToken token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser, token).build();
+                break;
+            case KERBEROS:
+                final String principal = kerberosService == null ? context.getProperty(KERBEROS_PRINCIPAL).getValue() : kerberosService.getPrincipal();
 
-        final AuthenticationToken token = getToken(type,context);
+                if (kerberosService != null) {
+                    this.kerberosUser = new KerberosKeytabUser(principal, kerberosService.getKeytab());
+                } else {
+                    this.kerberosUser = new KerberosPasswordUser(principal, context.getProperty(KERBEROS_PASSWORD).getValue());
+                }

Review comment:
       Optional, although I think it's much cleaner this way.
   
   ```suggestion
                   if (kerberosService == null) {
                       principal = context.getProperty(KERBEROS_PRINCIPAL).getValue();
                       this.kerberosUser = new KerberosPasswordUser(principal, context.getProperty(KERBEROS_PASSWORD).getValue());
                   } else {
                       principal = kerberosService.getPrincipal();
                       this.kerberosUser = new KerberosKeytabUser(principal, kerberosService.getKeytab());
                   }
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -50,52 +60,95 @@
  */
 @RequiresInstanceClassLoading
 @Tags({"accumulo", "client", "service"})
-@CapabilityDescription("A controller service for accessing an HBase client.")
+@CapabilityDescription("A controller service for accessing an Accumulo Client.")
 public class AccumuloService extends AbstractControllerService implements BaseAccumuloService {
 
-    private enum AuthenticationType{
+    private enum AuthenticationType {
         PASSWORD,
+        KERBEROS,
         NONE
     }
 
     protected static final PropertyDescriptor ZOOKEEPER_QUORUM = new PropertyDescriptor.Builder()
             .name("ZooKeeper Quorum")
+            .displayName("ZooKeeper Quorum")
             .description("Comma-separated list of ZooKeeper hosts for Accumulo.")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
     protected static final PropertyDescriptor INSTANCE_NAME = new PropertyDescriptor.Builder()
             .name("Instance Name")
+            .displayName("Instance Name")
             .description("Instance name of the Accumulo cluster")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
             .build();
 
+    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
+            .name("accumulo-authentication-type")
+            .displayName("Authentication Type")
+            .description("Authentication Type")
+            .allowableValues(AuthenticationType.values())
+            .defaultValue(AuthenticationType.PASSWORD.toString())
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .build();
 
     protected static final PropertyDescriptor ACCUMULO_USER = new PropertyDescriptor.Builder()
             .name("Accumulo User")
+            .displayName("Accumulo User")
             .description("Connecting user for Accumulo")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
     protected static final PropertyDescriptor ACCUMULO_PASSWORD = new PropertyDescriptor.Builder()
             .name("Accumulo Password")
-            .description("Connecting user's password when using the PASSWORD Authentication type")
+            .displayName("Accumulo Password")
+            .description("Connecting user's password")
             .sensitive(true)
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
             .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.PASSWORD.toString())
             .build();
 
-    protected static final PropertyDescriptor AUTHENTICATION_TYPE = new PropertyDescriptor.Builder()
-            .name("Authentication Type")
-            .description("Authentication Type")
-            .allowableValues(AuthenticationType.values())
-            .defaultValue(AuthenticationType.PASSWORD.toString())
+    protected static final PropertyDescriptor KERBEROS_CREDENTIALS_SERVICE = new PropertyDescriptor.Builder()
+            .name("kerberos-credentials-service")
+            .displayName("Kerberos Credentials Service")
+            .description("Specifies the Kerberos Credentials Controller Service that should be used for principal + keytab Kerberos authentication")
+            .identifiesControllerService(KerberosCredentialsService.class)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS.toString())
+            .build();
+
+    protected static final PropertyDescriptor KERBEROS_PRINCIPAL = new PropertyDescriptor.Builder()
+            .name("accumulo-kerberos-principal")
+            .displayName("Kerberos Principal")
+            .description("Kerberos Principal")
             .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
+            .dependsOn(AUTHENTICATION_TYPE, AuthenticationType.KERBEROS.toString())
             .build();
 
+    protected static final PropertyDescriptor KERBEROS_PASSWORD = new PropertyDescriptor.Builder()
+            .name("accumulo-kerberos-password")

Review comment:
       ```suggestion
               .name("kerberos-password")
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +204,108 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && !validationContext.getProperty(KERBEROS_PASSWORD).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Either Kerberos Password or Kerberos Credential Service must be set").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(KERBEROS_PASSWORD).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName())
+                            .explanation("Kerberos Password and Kerberos Credential Service should not be filled out at the same time").build());
+                } else if (validationContext.getProperty(KERBEROS_PASSWORD).isSet() && !validationContext.getProperty(KERBEROS_PRINCIPAL).isSet()) {
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_PRINCIPAL.getName())
+                            .explanation("Kerberos Principal must be supplied when principal + password Kerberos authentication is used").build());
+                } else if (validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet() && validationContext.getProperty(KERBEROS_PRINCIPAL).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_PRINCIPAL.getName())
+                            .explanation("Kerberos Principal (for password) should not be filled out when principal + keytab Kerberos authentication is used").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
     public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        final AuthenticationType authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                final AuthenticationToken token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser, token).build();
+                break;
+            case KERBEROS:
+                final String principal = kerberosService == null ? context.getProperty(KERBEROS_PRINCIPAL).getValue() : kerberosService.getPrincipal();

Review comment:
       ```suggestion
                   final String principal;
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -107,34 +160,35 @@
      */
     private List<PropertyDescriptor> properties;
 
+    private KerberosUser kerberosUser;
+
     @Override
-    protected void init(ControllerServiceInitializationContext config) throws InitializationException {
+    protected void init(ControllerServiceInitializationContext config) {
         List<PropertyDescriptor> props = new ArrayList<>();
         props.add(ZOOKEEPER_QUORUM);
         props.add(INSTANCE_NAME);
         props.add(ACCUMULO_USER);
-        props.add(AUTHENTICATION_TYPE);
         props.add(ACCUMULO_PASSWORD);
+        props.add(AUTHENTICATION_TYPE);
+        props.add(KERBEROS_CREDENTIALS_SERVICE);
+        props.add(KERBEROS_PRINCIPAL);
+        props.add(KERBEROS_PASSWORD);
+        props.add(ACCUMULO_SASL_QOP);
         properties = Collections.unmodifiableList(props);
     }
 
-    private AuthenticationToken getToken(final AuthenticationType type, final ConfigurationContext context){
-        switch(type){
-            case PASSWORD:
-                return new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
-            default:
-                return null;
-        }
-    }
-
     @Override
     public final List<PropertyDescriptor> getSupportedPropertyDescriptors() {

Review comment:
       ```suggestion
       @Override
       public final List<PropertyDescriptor> getSupportedPropertyDescriptors() {
           return properties;
       }
   ```

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -107,34 +160,35 @@
      */
     private List<PropertyDescriptor> properties;
 
+    private KerberosUser kerberosUser;
+
     @Override
-    protected void init(ControllerServiceInitializationContext config) throws InitializationException {
+    protected void init(ControllerServiceInitializationContext config) {
         List<PropertyDescriptor> props = new ArrayList<>();
         props.add(ZOOKEEPER_QUORUM);
         props.add(INSTANCE_NAME);
         props.add(ACCUMULO_USER);
-        props.add(AUTHENTICATION_TYPE);
         props.add(ACCUMULO_PASSWORD);
+        props.add(AUTHENTICATION_TYPE);

Review comment:
       I would move `props.add(AUTHENTICATION_TYPE);` above `props.add(ACCUMULO_USER);`




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] bbende commented on a change in pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#discussion_r607959529



##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -53,49 +58,73 @@
 @CapabilityDescription("A controller service for accessing an HBase client.")

Review comment:
       Change wording from "HBase client" to "Accumulo Client"

##########
File path: nifi-nar-bundles/nifi-accumulo-bundle/nifi-accumulo-services/src/main/java/org/apache/nifi/accumulo/controllerservices/AccumuloService.java
##########
@@ -150,61 +176,92 @@ private AuthenticationToken getToken(final AuthenticationType type, final Config
             problems.add(new ValidationResult.Builder().valid(false).subject(ZOOKEEPER_QUORUM.getName()).explanation("Zookeepers must be supplied").build());
         }
 
-        if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
-            problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied").build());
-        }
-
         final AuthenticationType type = validationContext.getProperty(
-                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.PASSWORD;
+                AUTHENTICATION_TYPE).isSet() ? AuthenticationType.valueOf( validationContext.getProperty(AUTHENTICATION_TYPE).getValue() ) : AuthenticationType.NONE;
 
         switch(type){
             case PASSWORD:
+                if (!validationContext.getProperty(ACCUMULO_USER).isSet()){
+                    problems.add(
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_USER.getName()).explanation("Accumulo user must be supplied for the Password Authentication type").build());
+                }
                 if (!validationContext.getProperty(ACCUMULO_PASSWORD).isSet()){
                     problems.add(
-                            new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Password must be supplied for the Password Authentication type").build());
+                            new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName())
+                                    .explanation("Password must be supplied for the Password Authentication type").build());
+                }
+                break;
+            case KERBEROS:
+                if (!validationContext.getProperty(KERBEROS_CREDENTIALS_SERVICE).isSet()){
+                    problems.add(new ValidationResult.Builder().valid(false).subject(KERBEROS_CREDENTIALS_SERVICE.getName())
+                            .explanation("Kerberos credential service must be supplied for the Kerberos Authentication type").build());
                 }
                 break;
             default:
-                problems.add(new ValidationResult.Builder().valid(false).subject(ACCUMULO_PASSWORD.getName()).explanation("Non supported Authentication type").build());
+                problems.add(new ValidationResult.Builder().valid(false).subject(AUTHENTICATION_TYPE.getName()).explanation("Non supported Authentication type").build());
         }
 
         return problems;
     }
 
     @OnEnabled
-    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException, InterruptedException {
-        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet() || !context.getProperty(ACCUMULO_USER).isSet()){
+    public void onEnabled(final ConfigurationContext context) throws InitializationException, IOException {
+        if (!context.getProperty(INSTANCE_NAME).isSet() || !context.getProperty(ZOOKEEPER_QUORUM).isSet()) {
             throw new InitializationException("Instance name and Zookeeper Quorum must be specified");
         }
 
-
-
+        final KerberosCredentialsService kerberosService = context.getProperty(KERBEROS_CREDENTIALS_SERVICE).asControllerService(KerberosCredentialsService.class);
         final String instanceName = context.getProperty(INSTANCE_NAME).evaluateAttributeExpressions().getValue();
         final String zookeepers = context.getProperty(ZOOKEEPER_QUORUM).evaluateAttributeExpressions().getValue();
-        final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
+        authType = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue());
+        AuthenticationToken token;
 
-        final AuthenticationType type = AuthenticationType.valueOf( context.getProperty(AUTHENTICATION_TYPE).getValue() );
+        final Properties clientConf = new Properties();
+        clientConf.setProperty("instance.zookeepers", zookeepers);
+        clientConf.setProperty("instance.name", instanceName);
 
+        switch(authType){
+            case PASSWORD:
+                final String accumuloUser = context.getProperty(ACCUMULO_USER).evaluateAttributeExpressions().getValue();
 
+                token = new PasswordToken(context.getProperty(ACCUMULO_PASSWORD).getValue());
 
-        final AuthenticationToken token = getToken(type,context);
+                this.client = Accumulo.newClient().from(clientConf).as(accumuloUser,token).build();
+                break;
+            case KERBEROS:
+                final  String principal = kerberosService.getPrincipal();
+
+                clientConf.setProperty("sasl.enabled", "true");
+                clientConf.setProperty("sasl.qop", context.getProperty(ACCUMULO_SASL_QOP).getValue());
+
+                //Client uses the currently logged in user's security context, so need to login first.
+                Configuration conf = new Configuration();
+                conf.set("hadoop.security.authentication", "kerberos");
+                UserGroupInformation.setConfiguration(conf);
+                UserGroupInformation.loginUserFromKeytab(principal, kerberosService.getKeytab());

Review comment:
       Something else to also consider is that there was an effort to add support for password-based kerberos login to many of the components that support kerberos. If we want to support that here, you can use the HBase service for guidance on how that was implemented...
   
   https://github.com/apache/nifi/blob/main/nifi-nar-bundles/nifi-standard-services/nifi-hbase_2-client-service-bundle/nifi-hbase_2-client-service/src/main/java/org/apache/nifi/hbase/HBase_2_ClientService.java#L372-L383




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [nifi] phrocker edited a comment on pull request #4973: NIFI-8373 Add Kerberos support to Accumulo processors

Posted by GitBox <gi...@apache.org>.
phrocker edited a comment on pull request #4973:
URL: https://github.com/apache/nifi/pull/4973#issuecomment-824166125


   @pvillard31 I will try and find some time to get this tested.  The code looks good, so I will see if I can spin an instance up to run this. thanks


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org