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/01 13:53:30 UTC
[GitHub] [nifi] exceptionfactory opened a new pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
exceptionfactory opened a new pull request #4968:
URL: https://github.com/apache/nifi/pull/4968
#### Description of PR
NIFI-8363 Implements a Single User `LoginIdentityProvider` and `Authorizer` as an incremental step toward a default secure standalone installation of NiFi. The `LoginIdentityProvider` class includes the following features:
- Reads and writes username and hashed password in `login-identity-providers.xml`
- Generates random username using `java.util.UUID.randomUUID()`
- Generates random password of using `java.security.SecureRandom` with Base64 encoding
- Writes generated password hash using bcrypt
The implementation is not intended for production use, but provides a basic level of security for standalone installations. Future changes will incorporate updates to default configuration files so that this implementation can be reviewed independently. Verifying runtime behavior requires the following steps:
1. Copy `login-identity-providers.xml` from the test resources directory to the NiFi `conf` directory
2. Create an `authorizer` definition in `conf/authorizers.xml` with the following elements:
```
<authorizer>
<identifier>single-user-authorizer</identifier>
<class>org.apache.nifi.authorization.single.user.SingleUserAuthorizer</class>
</authorizer>
```
3. Set `nifi.security.user.login.identity.provider=single-user-provider` in `nifi.properties`
4. Set `nifi.security.user.authorizer=single-user-authorizer` in `nifi.properties`
5. Set `nifi.web.https.port` and `nifi.security` keystore and truststore properties to enable HTTPS
6. Start NiFi and search `nifi-app.log` for `Generated Username` and `Generated Password`
7. Login with NiFi using the generated credentials
In order to streamline the review of the contribution we ask you
to ensure the following steps have been taken:
### For all changes:
- [X] Is there a JIRA ticket associated with this PR? Is it referenced
in the commit message?
- [X] 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.
- [X] Has your PR been rebased against the latest commit within the target branch (typically `main`)?
- [X] 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:
- [X] Have you ensured that the full suite of tests is executed via `mvn -Pcontrib-check clean install` at the root `nifi` folder?
- [X] Have you written or updated unit tests to verify your changes?
- [X] Have you verified that the full build is successful on JDK 8?
- [X] 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] bbende commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605752399
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Is there some way this could be linked together with the identity from the SingleUserLoginIdentityProvider?
This is really more of a no-op authorizer that just authorizes everything regardless of the user identity. For example, if a request was made with a client cert then it would be authorized to do anything, even if that identity was not the username of the SingleUserLoginIdentityProvider. Maybe not an issue if this is only intended for local use.
I'm not exactly sure how the coordination between identity providers and authorizers would work though, since they purposely don't know about each other. The only idea that comes to mind is if the single-user identity came from nifi.properties since they both have access to that. Alternatively, could maybe use the existing file-based providers, but have someway to setup the initial user / initial admin with the single-user identity, then eliminate the need for a new Authorizer implementation.
--
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] exceptionfactory commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
exceptionfactory commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605794432
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Thanks for the additional feedback, it is a challenge to find the right balance of security and ease of use for this implementation. I would prefer to avoid introducing new properties into `nifi.properties` so that this can be remain modular.
The concern about authorizing all actions with the `SingleUserAuthorizer` is worth considering. What about introducing a way to make it depend on the `SingleUserLoginIdentityProvider` being configured? At a basic level, this could require having `nifi.security.user.login.identity.provider` set to `single-user-provider` and ensuring that the expected class is configured as a provider in `login-identity-providers.xml`? Something along that line would ensure that the `SingleUserAuthorizer` only works with `SingleUserLoginIdentityProvider` and cannot be used with other authentication strategies.
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Thanks for the additional feedback, it is a challenge to find the right balance of security and ease of use for this implementation. I would prefer to avoid introducing new properties into `nifi.properties` so that this can remain modular.
The concern about authorizing all actions with the `SingleUserAuthorizer` is worth considering. What about introducing a way to make it depend on the `SingleUserLoginIdentityProvider` being configured? At a basic level, this could require having `nifi.security.user.login.identity.provider` set to `single-user-provider` and ensuring that the expected class is configured as a provider in `login-identity-providers.xml`? Something along that line would ensure that the `SingleUserAuthorizer` only works with `SingleUserLoginIdentityProvider` and cannot be used with other authentication strategies.
--
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 #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605801577
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Yea that seems like a reasonable way to ensure the new authorizer is only used for the intended situation.
--
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 #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r610812401
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authentication.single.user.SingleUserLoginIdentityProvider;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.annotation.AuthorizerContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.util.NiFiProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Single User Authorizer requires Single User Login Identity Provider to be configured and authorizes all requests
+ */
+public class SingleUserAuthorizer implements Authorizer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SingleUserAuthorizer.class);
+
+ private static final String REQUIRED_PROVIDER = SingleUserLoginIdentityProvider.class.getName();
+
+ private static final String IDENTIFIER_TAG = "identifier";
+
+ private static final String CLASS_TAG = "class";
+
+ /**
+ * Set NiFi Properties using method injection
+ *
+ * @param niFiProperties NiFi Properties
+ */
+ @AuthorizerContext
+ public void setProperties(final NiFiProperties niFiProperties) {
+ final File configuration = niFiProperties.getLoginIdentityProviderConfigurationFile();
+ final String identifier = niFiProperties.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER);
+ if (isSingleUserLoginIdentityProviderConfigured(identifier, configuration)) {
+ LOGGER.debug("Required Login Identity Provider Configured [{}]", REQUIRED_PROVIDER);
+ } else {
+ final String message = String.format("%s requires %s to be configured", getClass().getSimpleName(), REQUIRED_PROVIDER);
+ throw new AuthorizerCreationException(message);
+ }
+ }
+
+ @Override
+ public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
+ return AuthorizationResult.approved();
+ }
+
+ @Override
+ public void initialize(final AuthorizerInitializationContext initializationContext) {
+ LOGGER.info("Initializing Authorizer");
+ }
+
+ @Override
+ public void onConfigured(final AuthorizerConfigurationContext configurationContext) {
+ LOGGER.info("Configuring Authorizer");
+ }
+
+ @Override
+ public void preDestruction() {
+ LOGGER.info("Destroying Authorizer");
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final File configuration) {
+ try (final InputStream inputStream = new FileInputStream(configuration)) {
+ final XMLEventReader reader = getProvidersReader(inputStream);
+ final boolean configured = isSingleUserLoginIdentityProviderConfigured(configuredIdentifier, reader);
+ reader.close();
+ return configured;
+ } catch (final XMLStreamException | IOException e) {
+ throw new AuthorizerCreationException("Failed to read Login Identity Providers Configuration", e);
+ }
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final XMLEventReader reader) throws XMLStreamException {
+ boolean providerConfigured = false;
+
+ boolean identifierFound = false;
+ while (reader.hasNext()) {
+ final XMLEvent event = reader.nextEvent();
+ if (isStartElement(event, IDENTIFIER_TAG)) {
+ final String providerIdentifier = reader.getElementText().trim();
+ identifierFound = configuredIdentifier.equals(providerIdentifier);
Review comment:
I was testing to see if start up failed when using the authorizer without the identity provider, and I happened to test it by commenting out the property in nifi.properties that specifies the identity provider identifier, which then caused this line to NPE.
--
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 #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r610894056
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authentication.single.user.SingleUserLoginIdentityProvider;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.annotation.AuthorizerContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.util.NiFiProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Single User Authorizer requires Single User Login Identity Provider to be configured and authorizes all requests
+ */
+public class SingleUserAuthorizer implements Authorizer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SingleUserAuthorizer.class);
+
+ private static final String REQUIRED_PROVIDER = SingleUserLoginIdentityProvider.class.getName();
+
+ private static final String IDENTIFIER_TAG = "identifier";
+
+ private static final String CLASS_TAG = "class";
+
+ /**
+ * Set NiFi Properties using method injection
+ *
+ * @param niFiProperties NiFi Properties
+ */
+ @AuthorizerContext
+ public void setProperties(final NiFiProperties niFiProperties) {
+ final File configuration = niFiProperties.getLoginIdentityProviderConfigurationFile();
+ final String identifier = niFiProperties.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER);
+ if (isSingleUserLoginIdentityProviderConfigured(identifier, configuration)) {
+ LOGGER.debug("Required Login Identity Provider Configured [{}]", REQUIRED_PROVIDER);
+ } else {
+ final String message = String.format("%s requires %s to be configured", getClass().getSimpleName(), REQUIRED_PROVIDER);
+ throw new AuthorizerCreationException(message);
+ }
+ }
+
+ @Override
+ public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
+ return AuthorizationResult.approved();
+ }
+
+ @Override
+ public void initialize(final AuthorizerInitializationContext initializationContext) {
+ LOGGER.info("Initializing Authorizer");
+ }
+
+ @Override
+ public void onConfigured(final AuthorizerConfigurationContext configurationContext) {
+ LOGGER.info("Configuring Authorizer");
+ }
+
+ @Override
+ public void preDestruction() {
+ LOGGER.info("Destroying Authorizer");
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final File configuration) {
+ try (final InputStream inputStream = new FileInputStream(configuration)) {
+ final XMLEventReader reader = getProvidersReader(inputStream);
+ final boolean configured = isSingleUserLoginIdentityProviderConfigured(configuredIdentifier, reader);
+ reader.close();
+ return configured;
+ } catch (final XMLStreamException | IOException e) {
+ throw new AuthorizerCreationException("Failed to read Login Identity Providers Configuration", e);
+ }
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final XMLEventReader reader) throws XMLStreamException {
+ boolean providerConfigured = false;
+
+ boolean identifierFound = false;
+ while (reader.hasNext()) {
+ final XMLEvent event = reader.nextEvent();
+ if (isStartElement(event, IDENTIFIER_TAG)) {
+ final String providerIdentifier = reader.getElementText().trim();
+ identifierFound = configuredIdentifier.equals(providerIdentifier);
Review comment:
Sounds good, had a feeling that you may have not included that stuff on purpose.
--
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] exceptionfactory commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
exceptionfactory commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605770267
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Thanks for the feedback @bbende! I considered some options for integration with the the existing file-based providers, but part of the challenge is having the generated username available to the file-based providers.
One alternative solution is to use a standard default username and set that value in the `Initial Admin Identity` property of the file-based provider. That would remove the need for the username generation in the `SingleUserLoginIdentityProvider`, but it would also set a default username across the board.
On the other hand, this question could be addressed in future issues when it comes to changing the default configuration files. With the goal here of providing single user access, a user would have to perform additional work to authenticate using client certificates, so I'm not sure if authorizing client certificate access should be a concern.
--
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 merged pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
bbende merged pull request #4968:
URL: https://github.com/apache/nifi/pull/4968
--
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] exceptionfactory commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
exceptionfactory commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605844359
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
@bbende I pushed an update so that `SingleUserAuthorizer` reads the configured `nifi.security.user.login.identity.provider` and parses `login-identity-providers.xml` to require that the provider class is `SingleUserLoginIdentityProvider`. This should effectively prevent `SingleUserAuthorizer` from being used with any other login configuration.
Please let me know if you have any other comments or concerns.
--
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] exceptionfactory commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
exceptionfactory commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r610886621
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authentication.single.user.SingleUserLoginIdentityProvider;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.annotation.AuthorizerContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.util.NiFiProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Single User Authorizer requires Single User Login Identity Provider to be configured and authorizes all requests
+ */
+public class SingleUserAuthorizer implements Authorizer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SingleUserAuthorizer.class);
+
+ private static final String REQUIRED_PROVIDER = SingleUserLoginIdentityProvider.class.getName();
+
+ private static final String IDENTIFIER_TAG = "identifier";
+
+ private static final String CLASS_TAG = "class";
+
+ /**
+ * Set NiFi Properties using method injection
+ *
+ * @param niFiProperties NiFi Properties
+ */
+ @AuthorizerContext
+ public void setProperties(final NiFiProperties niFiProperties) {
+ final File configuration = niFiProperties.getLoginIdentityProviderConfigurationFile();
+ final String identifier = niFiProperties.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER);
+ if (isSingleUserLoginIdentityProviderConfigured(identifier, configuration)) {
+ LOGGER.debug("Required Login Identity Provider Configured [{}]", REQUIRED_PROVIDER);
+ } else {
+ final String message = String.format("%s requires %s to be configured", getClass().getSimpleName(), REQUIRED_PROVIDER);
+ throw new AuthorizerCreationException(message);
+ }
+ }
+
+ @Override
+ public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
+ return AuthorizationResult.approved();
+ }
+
+ @Override
+ public void initialize(final AuthorizerInitializationContext initializationContext) {
+ LOGGER.info("Initializing Authorizer");
+ }
+
+ @Override
+ public void onConfigured(final AuthorizerConfigurationContext configurationContext) {
+ LOGGER.info("Configuring Authorizer");
+ }
+
+ @Override
+ public void preDestruction() {
+ LOGGER.info("Destroying Authorizer");
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final File configuration) {
+ try (final InputStream inputStream = new FileInputStream(configuration)) {
+ final XMLEventReader reader = getProvidersReader(inputStream);
+ final boolean configured = isSingleUserLoginIdentityProviderConfigured(configuredIdentifier, reader);
+ reader.close();
+ return configured;
+ } catch (final XMLStreamException | IOException e) {
+ throw new AuthorizerCreationException("Failed to read Login Identity Providers Configuration", e);
+ }
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final XMLEventReader reader) throws XMLStreamException {
+ boolean providerConfigured = false;
+
+ boolean identifierFound = false;
+ while (reader.hasNext()) {
+ final XMLEvent event = reader.nextEvent();
+ if (isStartElement(event, IDENTIFIER_TAG)) {
+ final String providerIdentifier = reader.getElementText().trim();
+ identifierFound = configuredIdentifier.equals(providerIdentifier);
Review comment:
> Just getting back to this... was able to set everything up and get logged in with the generated username and password, nice work!
>
> Two additional comments to the one in-line comment...
>
> 1. The NAR for the new bundle was not included in the assembly by default. Not sure if this was on purpose to keep the size of the overall distro down, but I would imagine we want this by default if we want to work towards a secure-by-default config.
>
> 2. Can/should we update the default config files for login-identity-providers.xml and authorizers.xml with the commented out single-user providers with descriptions of usage and properties? This would make it easier for a user to enable this config.
Thanks for the additional feedback @bbende! I left out this NAR from the assembly and did not introduce the provider definition in this PR with the goal of adding those elements in a separate PR that also introduces HTTPS as part of the default configuration. Since this is a subtask of NIFI-8220, I would like to get the components parts implemented, and then introduce the default configuration separately. How does that sound?
I will add some checking around this particular line to handle the potential NPE you described.
--
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 #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
bbende commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605781607
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Yea I agree that the client cert example is probably not realistic, but I guess my general concern was just providing an authorizer that allows everything. I assume the goal here is to eventually have this enabled by default, so I am picturing a user who is trying to switch away from the defaults and not knowing, or forgetting, and leaving this authorizer enabled.
I think the only way to make the username available across the board is if the single-user concept was in the framework at a higher level then the provider implementations, and by the time the provider's load their config, it was already populated with the single-user stuff.
Something like in nifi.properties...
```
nifi.security.single.user.mode.enabled=true
nifi.security.single.user.identity=
nifi.security.single.user.password=
```
The framework would generate these values and write them out to nifi.properties, then the identity provider and authorizer would get an instance of NiFiProperties and get these values and fail if they weren't populated. Maybe password would not be in nifi.properties and still in the identity provider (?).
I obviously haven't put that much thought into this, and not trying to derail your efforts, just throwing out ideas. If you don't think there is sufficient concern about the authorizer, I won't get too hung up on it.
--
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] exceptionfactory commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
exceptionfactory commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r610898948
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authentication.single.user.SingleUserLoginIdentityProvider;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.annotation.AuthorizerContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.util.NiFiProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Single User Authorizer requires Single User Login Identity Provider to be configured and authorizes all requests
+ */
+public class SingleUserAuthorizer implements Authorizer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SingleUserAuthorizer.class);
+
+ private static final String REQUIRED_PROVIDER = SingleUserLoginIdentityProvider.class.getName();
+
+ private static final String IDENTIFIER_TAG = "identifier";
+
+ private static final String CLASS_TAG = "class";
+
+ /**
+ * Set NiFi Properties using method injection
+ *
+ * @param niFiProperties NiFi Properties
+ */
+ @AuthorizerContext
+ public void setProperties(final NiFiProperties niFiProperties) {
+ final File configuration = niFiProperties.getLoginIdentityProviderConfigurationFile();
+ final String identifier = niFiProperties.getProperty(NiFiProperties.SECURITY_USER_LOGIN_IDENTITY_PROVIDER);
+ if (isSingleUserLoginIdentityProviderConfigured(identifier, configuration)) {
+ LOGGER.debug("Required Login Identity Provider Configured [{}]", REQUIRED_PROVIDER);
+ } else {
+ final String message = String.format("%s requires %s to be configured", getClass().getSimpleName(), REQUIRED_PROVIDER);
+ throw new AuthorizerCreationException(message);
+ }
+ }
+
+ @Override
+ public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
+ return AuthorizationResult.approved();
+ }
+
+ @Override
+ public void initialize(final AuthorizerInitializationContext initializationContext) {
+ LOGGER.info("Initializing Authorizer");
+ }
+
+ @Override
+ public void onConfigured(final AuthorizerConfigurationContext configurationContext) {
+ LOGGER.info("Configuring Authorizer");
+ }
+
+ @Override
+ public void preDestruction() {
+ LOGGER.info("Destroying Authorizer");
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final File configuration) {
+ try (final InputStream inputStream = new FileInputStream(configuration)) {
+ final XMLEventReader reader = getProvidersReader(inputStream);
+ final boolean configured = isSingleUserLoginIdentityProviderConfigured(configuredIdentifier, reader);
+ reader.close();
+ return configured;
+ } catch (final XMLStreamException | IOException e) {
+ throw new AuthorizerCreationException("Failed to read Login Identity Providers Configuration", e);
+ }
+ }
+
+ private boolean isSingleUserLoginIdentityProviderConfigured(final String configuredIdentifier, final XMLEventReader reader) throws XMLStreamException {
+ boolean providerConfigured = false;
+
+ boolean identifierFound = false;
+ while (reader.hasNext()) {
+ final XMLEvent event = reader.nextEvent();
+ if (isStartElement(event, IDENTIFIER_TAG)) {
+ final String providerIdentifier = reader.getElementText().trim();
+ identifierFound = configuredIdentifier.equals(providerIdentifier);
Review comment:
Thanks for the confirmation, I just pushed an update to avoid the NPE with a unit test to confirm that it works as expected.
--
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] exceptionfactory commented on a change in pull request #4968: NIFI-8363 Added Single User Login Identity Provider and Authorizer
Posted by GitBox <gi...@apache.org>.
exceptionfactory commented on a change in pull request #4968:
URL: https://github.com/apache/nifi/pull/4968#discussion_r605804403
##########
File path: nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
##########
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization.single.user;
+
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Single User Authorizer
+ */
+public class SingleUserAuthorizer implements Authorizer {
Review comment:
Thanks @bbende, I will change `SingleUserAuthorizer` to check for `SingleUserLoginIdentityProvider`.
--
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