You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2016/07/12 15:21:25 UTC
[2/2] nifi git commit: NIFI-2003 Creating abstract authentication
provider and incorporating into existing providers NIFI-2201 Add support for
seeding cluster nodes in authorizations.xml - Passing client address along in
user context on authorization req
NIFI-2003 Creating abstract authentication provider and incorporating into existing providers
NIFI-2201 Add support for seeding cluster nodes in authorizations.xml
- Passing client address along in user context on authorization requests
- This closes #628
Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/ba763b95
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/ba763b95
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/ba763b95
Branch: refs/heads/master
Commit: ba763b95e8147be159a39031b9c7396e88293ebd
Parents: 4b9df7d
Author: Bryan Bende <bb...@apache.org>
Authored: Thu Jun 16 11:51:00 2016 -0400
Committer: Matt Gilman <ma...@gmail.com>
Committed: Tue Jul 12 11:20:29 2016 -0400
----------------------------------------------------------------------
.../AbstractPolicyBasedAuthorizer.java | 24 ++-
.../nifi/authorization/UserContextKeys.java | 26 +++
.../authorization/UsersAndAccessPolicies.java | 7 +-
.../authorization/resource/Authorizable.java | 20 +-
.../nifi/authorization/user/NiFiUser.java | 6 +
.../TestAbstractPolicyBasedAuthorizer.java | 23 +--
.../org/apache/nifi/util/NiFiProperties.java | 2 +
.../authorization/AuthorizationsHolder.java | 16 +-
.../nifi/authorization/FileAuthorizer.java | 100 +++++++--
.../nifi/authorization/FileAuthorizerTest.java | 56 ++++-
.../authorization/user/StandardNiFiUser.java | 17 +-
.../org/apache/nifi/controller/Template.java | 13 +-
.../src/main/resources/conf/authorizations.xml | 55 +----
.../src/main/resources/conf/authorizers.xml | 23 +++
.../src/main/resources/conf/nifi.properties | 10 +
.../StandardNiFiWebConfigurationContext.java | 10 +
.../org/apache/nifi/web/api/AccessResource.java | 16 +-
.../apache/nifi/web/api/ControllerResource.java | 12 ++
.../apache/nifi/web/api/CountersResource.java | 12 ++
.../org/apache/nifi/web/api/FlowResource.java | 19 ++
.../apache/nifi/web/api/ProvenanceResource.java | 10 +
.../apache/nifi/web/api/ResourceResource.java | 12 ++
.../nifi/web/api/SystemDiagnosticsResource.java | 12 ++
.../nifi/web/controller/ControllerFacade.java | 6 +-
.../web/dao/impl/StandardConnectionDAO.java | 12 ++
.../security/NiFiAuthenticationProvider.java | 185 +++++++++++++++++
.../NiFiAuthenticationRequestToken.java | 41 ++++
.../security/jwt/JwtAuthenticationFilter.java | 2 +-
.../security/jwt/JwtAuthenticationProvider.java | 10 +-
.../jwt/JwtAuthenticationRequestToken.java | 9 +-
.../security/otp/OtpAuthenticationFilter.java | 4 +-
.../security/otp/OtpAuthenticationProvider.java | 10 +-
.../otp/OtpAuthenticationRequestToken.java | 10 +-
.../security/x509/X509AuthenticationFilter.java | 2 +-
.../x509/X509AuthenticationProvider.java | 35 +++-
.../x509/X509AuthenticationRequestToken.java | 8 +-
.../resources/nifi-web-security-context.xml | 3 +
.../NiFiAuthenticationProviderTest.java | 203 +++++++++++++++++++
.../otp/OtpAuthenticationProviderTest.java | 9 +-
.../TestPersistentProvenanceRepository.java | 6 +
.../TestVolatileProvenanceRepository.java | 5 +
41 files changed, 915 insertions(+), 146 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
index b173155..8fbe0fb 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
@@ -105,31 +105,33 @@ public abstract class AbstractPolicyBasedAuthorizer implements Authorizer {
final UsersAndAccessPolicies usersAndAccessPolicies = getUsersAndAccessPolicies();
final String resourceIdentifier = request.getResource().getIdentifier();
- final Set<AccessPolicy> policies = usersAndAccessPolicies.getAccessPolicies(resourceIdentifier);
- if (policies == null || policies.isEmpty()) {
+ final AccessPolicy policy = usersAndAccessPolicies.getAccessPolicy(resourceIdentifier, request.getAction());
+ if (policy == null) {
return AuthorizationResult.resourceNotFound();
}
final User user = usersAndAccessPolicies.getUser(request.getIdentity());
-
if (user == null) {
return AuthorizationResult.denied("Unknown user with identity " + request.getIdentity());
}
final Set<Group> userGroups = usersAndAccessPolicies.getGroups(user.getIdentity());
-
- for (AccessPolicy policy : policies) {
- final boolean containsUser = policy.getUsers().contains(user.getIdentifier());
- if (policy.getAction() == request.getAction() && (containsUser || containsGroup(userGroups, policy)) ) {
- return AuthorizationResult.approved();
- }
+ if (policy.getUsers().contains(user.getIdentifier()) || containsGroup(userGroups, policy)) {
+ return AuthorizationResult.approved();
}
+
return AuthorizationResult.denied();
}
-
- private boolean containsGroup(Set<Group> userGroups, final AccessPolicy policy) {
+ /**
+ * Determines if the policy contains one of the user's groups.
+ *
+ * @param userGroups the set of the user's groups
+ * @param policy the policy
+ * @return true if one of the Groups in userGroups is contained in the policy
+ */
+ private boolean containsGroup(final Set<Group> userGroups, final AccessPolicy policy) {
if (userGroups.isEmpty() || policy.getGroups().isEmpty()) {
return false;
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java b/nifi-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java
new file mode 100644
index 0000000..fca4b74
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/UserContextKeys.java
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+/**
+ * Constants for keys that can be passed in the AuthorizationRequest user context Map.
+ */
+public enum UserContextKeys {
+
+ CLIENT_ADDRESS;
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java b/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
index d7a825c..552b753 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/UsersAndAccessPolicies.java
@@ -25,12 +25,13 @@ import java.util.Set;
public interface UsersAndAccessPolicies {
/**
- * Retrieves the set of access policies for a given resource.
+ * Retrieves the set of access policies for a given resource and action.
*
* @param resourceIdentifier the resource identifier to retrieve policies for
- * @return the set of access policies for the given resource
+ * @param action the action to retrieve policies for
+ * @return the access policy for the given resource and action
*/
- public Set<AccessPolicy> getAccessPolicies(final String resourceIdentifier);
+ public AccessPolicy getAccessPolicy(final String resourceIdentifier, final RequestAction action);
/**
* Retrieves a user by an identity string.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
index 90374dd..7cb21ae 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
@@ -23,9 +23,11 @@ import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.user.NiFiUser;
import java.util.Map;
+import java.util.HashMap;
public interface Authorizable {
@@ -67,7 +69,13 @@ public interface Authorizable {
* @return is authorized
*/
default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action, NiFiUser user, Map<String, String> resourceContext) {
- // TODO - include user details context
+ final Map<String,String> userContext;
+ if (user.getClientAddress() != null && !user.getClientAddress().trim().isEmpty()) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
// build the request
final AuthorizationRequest request = new AuthorizationRequest.Builder()
@@ -77,6 +85,7 @@ public interface Authorizable {
.action(action)
.resource(getResource())
.resourceContext(resourceContext)
+ .userContext(userContext)
.build();
// perform the authorization
@@ -119,7 +128,13 @@ public interface Authorizable {
* @param resourceContext resource context
*/
default void authorize(Authorizer authorizer, RequestAction action, NiFiUser user, Map<String, String> resourceContext) throws AccessDeniedException {
- // TODO - include user details context
+ final Map<String,String> userContext;
+ if (user.getClientAddress() != null && !user.getClientAddress().trim().isEmpty()) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity(user.getIdentity())
@@ -128,6 +143,7 @@ public interface Authorizable {
.action(action)
.resource(getResource())
.resourceContext(resourceContext)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
index 9ec04e2..c450bc4 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
@@ -36,4 +36,10 @@ public interface NiFiUser {
* @return <code>true</code> if the user is the unauthenticated Anonymous user
*/
boolean isAnonymous();
+
+ /**
+ * @return the address of the client that made the request which created this user
+ */
+ String getClientAddress();
+
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
index 6be3f1a..b173d3d 100644
--- a/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
+++ b/nifi-api/src/test/java/org/apache/nifi/authorization/TestAbstractPolicyBasedAuthorizer.java
@@ -54,15 +54,14 @@ public class TestAbstractPolicyBasedAuthorizer {
final String userIdentifier = "userIdentifier1";
final String userIdentity = "userIdentity1";
- final Set<AccessPolicy> policiesForResource = new HashSet<>();
- policiesForResource.add(new AccessPolicy.Builder()
+ final AccessPolicy policy = new AccessPolicy.Builder()
.identifier("1")
.resource(TEST_RESOURCE.getIdentifier())
.addUser(userIdentifier)
.action(RequestAction.READ)
- .build());
+ .build();
- when(usersAndAccessPolicies.getAccessPolicies(TEST_RESOURCE.getIdentifier())).thenReturn(policiesForResource);
+ when(usersAndAccessPolicies.getAccessPolicy(TEST_RESOURCE.getIdentifier(), RequestAction.READ)).thenReturn(policy);
final User user = new User.Builder()
.identity(userIdentity)
@@ -92,15 +91,14 @@ public class TestAbstractPolicyBasedAuthorizer {
final String userIdentity = "userIdentity1";
final String groupIdentifier = "groupIdentifier1";
- final Set<AccessPolicy> policiesForResource = new HashSet<>();
- policiesForResource.add(new AccessPolicy.Builder()
+ final AccessPolicy policy = new AccessPolicy.Builder()
.identifier("1")
.resource(TEST_RESOURCE.getIdentifier())
.addGroup(groupIdentifier)
.action(RequestAction.READ)
- .build());
+ .build();
- when(usersAndAccessPolicies.getAccessPolicies(TEST_RESOURCE.getIdentifier())).thenReturn(policiesForResource);
+ when(usersAndAccessPolicies.getAccessPolicy(TEST_RESOURCE.getIdentifier(), RequestAction.READ)).thenReturn(policy);
final User user = new User.Builder()
.identity(userIdentity)
@@ -137,15 +135,14 @@ public class TestAbstractPolicyBasedAuthorizer {
final String userIdentifier = "userIdentifier1";
final String userIdentity = "userIdentity1";
- final Set<AccessPolicy> policiesForResource = new HashSet<>();
- policiesForResource.add(new AccessPolicy.Builder()
+ final AccessPolicy policy = new AccessPolicy.Builder()
.identifier("1")
.resource(TEST_RESOURCE.getIdentifier())
.addUser("NOT_USER_1")
.action(RequestAction.READ)
- .build());
+ .build();
- when(usersAndAccessPolicies.getAccessPolicies(TEST_RESOURCE.getIdentifier())).thenReturn(policiesForResource);
+ when(usersAndAccessPolicies.getAccessPolicy(TEST_RESOURCE.getIdentifier(), RequestAction.READ)).thenReturn(policy);
final User user = new User.Builder()
.identity(userIdentity)
@@ -171,7 +168,7 @@ public class TestAbstractPolicyBasedAuthorizer {
UsersAndAccessPolicies usersAndAccessPolicies = Mockito.mock(UsersAndAccessPolicies.class);
when(authorizer.getUsersAndAccessPolicies()).thenReturn(usersAndAccessPolicies);
- when(usersAndAccessPolicies.getAccessPolicies(TEST_RESOURCE.getIdentifier())).thenReturn(new HashSet<>());
+ when(usersAndAccessPolicies.getAccessPolicy(TEST_RESOURCE.getIdentifier(), RequestAction.READ)).thenReturn(null);
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity("userIdentity")
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
index 2e84c5b..3a619cb 100644
--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
+++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
@@ -135,6 +135,8 @@ public class NiFiProperties extends Properties {
public static final String SECURITY_CLUSTER_AUTHORITY_PROVIDER_THREADS = "nifi.security.cluster.authority.provider.threads";
public static final String SECURITY_OCSP_RESPONDER_URL = "nifi.security.ocsp.responder.url";
public static final String SECURITY_OCSP_RESPONDER_CERTIFICATE = "nifi.security.ocsp.responder.certificate";
+ public static final String SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX = "nifi.security.identity.mapping.pattern.";
+ public static final String SECURITY_IDENTITY_MAPPING_VALUE_PREFIX = "nifi.security.identity.mapping.value.";
// web properties
public static final String WEB_WAR_DIR = "nifi.web.war.directory";
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
index 13adedc..383281d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizationsHolder.java
@@ -337,11 +337,23 @@ public class AuthorizationsHolder implements UsersAndAccessPolicies {
}
@Override
- public Set<AccessPolicy> getAccessPolicies(String resourceIdentifier) {
+ public AccessPolicy getAccessPolicy(final String resourceIdentifier, final RequestAction action) {
if (resourceIdentifier == null) {
throw new IllegalArgumentException("Resource Identifier cannot be null");
}
- return policiesByResource.get(resourceIdentifier);
+
+ final Set<AccessPolicy> resourcePolicies = policiesByResource.get(resourceIdentifier);
+ if (resourcePolicies == null) {
+ return null;
+ }
+
+ for (AccessPolicy accessPolicy : resourcePolicies) {
+ if (accessPolicy.getAction() == action) {
+ return accessPolicy;
+ }
+ }
+
+ return null;
}
@Override
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
index c11dc40..a672b30 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizer.java
@@ -66,6 +66,8 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
/**
@@ -103,6 +105,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
static final String PROP_AUTHORIZATIONS_FILE = "Authorizations File";
static final String PROP_INITIAL_ADMIN_IDENTITY = "Initial Admin Identity";
static final String PROP_LEGACY_AUTHORIZED_USERS_FILE = "Legacy Authorized Users File";
+ static final Pattern NODE_IDENTITY_PATTERN = Pattern.compile("Node Identity \\S+");
private Schema flowSchema;
private Schema usersSchema;
@@ -114,6 +117,7 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
private String rootGroupId;
private String initialAdminIdentity;
private String legacyAuthorizedUsersFile;
+ private Set<String> nodeIdentities;
private final AtomicReference<AuthorizationsHolder> authorizationsHolder = new AtomicReference<>();
@@ -169,12 +173,23 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
}
}
+ // get the value of the initial admin identity
final PropertyValue initialAdminIdentityProp = configurationContext.getProperty(PROP_INITIAL_ADMIN_IDENTITY);
initialAdminIdentity = initialAdminIdentityProp == null ? null : initialAdminIdentityProp.getValue();
+ // get the value of the legacy authorized users file
final PropertyValue legacyAuthorizedUsersProp = configurationContext.getProperty(PROP_LEGACY_AUTHORIZED_USERS_FILE);
legacyAuthorizedUsersFile = legacyAuthorizedUsersProp == null ? null : legacyAuthorizedUsersProp.getValue();
+ // extract any node identities
+ nodeIdentities = new HashSet<>();
+ for (Map.Entry<String,String> entry : configurationContext.getProperties().entrySet()) {
+ Matcher matcher = NODE_IDENTITY_PATTERN.matcher(entry.getKey());
+ if (matcher.matches() && !StringUtils.isBlank(entry.getValue())) {
+ nodeIdentities.add(entry.getValue());
+ }
+ }
+
// load the authorizations
load();
@@ -235,6 +250,8 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
convertLegacyAuthorizedUsers(authorizations);
}
+ populateNodes(authorizations);
+
// save any changes that were made and repopulate the holder
saveAndRefreshHolder(authorizations);
} else {
@@ -338,6 +355,38 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
}
/**
+ * Creates a user for each node and gives the nodes write permission to /proxy.
+ *
+ * @param authorizations the overall authorizations
+ */
+ private void populateNodes(Authorizations authorizations) {
+ for (String nodeIdentity : nodeIdentities) {
+ // see if we have an existing user for the given node identity
+ org.apache.nifi.authorization.file.generated.User jaxbNodeUser = null;
+ for (org.apache.nifi.authorization.file.generated.User user : authorizations.getUsers().getUser()) {
+ if (user.getIdentity().equals(nodeIdentity)) {
+ jaxbNodeUser = user;
+ break;
+ }
+ }
+
+ // if we didn't find an existing user then create a new one
+ if (jaxbNodeUser == null) {
+ // generate an identifier and add a User with the given identifier and identity
+ final UUID nodeIdentifier = UUID.nameUUIDFromBytes(nodeIdentity.getBytes(StandardCharsets.UTF_8));
+ final User nodeUser = new User.Builder().identifier(nodeIdentifier.toString()).identity(nodeIdentity).build();
+
+ jaxbNodeUser = createJAXBUser(nodeUser);
+ authorizations.getUsers().getUser().add(jaxbNodeUser);
+ }
+
+ // grant access to the proxy resource
+ addAccessPolicy(authorizations, ResourceType.Proxy.getValue(), jaxbNodeUser.getIdentifier(), READ_CODE);
+ addAccessPolicy(authorizations, ResourceType.Proxy.getValue(), jaxbNodeUser.getIdentifier(), WRITE_CODE);
+ }
+ }
+
+ /**
* Unmarshalls an existing authorized-users.xml and converts the object model to the new model.
*
* @param authorizations the current Authorizations instance that users, groups, and policies will be added to
@@ -509,25 +558,42 @@ public class FileAuthorizer extends AbstractPolicyBasedAuthorizer {
* @param action the action for the policy
*/
private void addAccessPolicy(final Authorizations authorizations, final String resource, final String identity, final String action) {
- final String uuidSeed = resource + identity;
- final UUID policyIdentifier = UUID.nameUUIDFromBytes(uuidSeed.getBytes(StandardCharsets.UTF_8));
-
- final AccessPolicy.Builder builder = new AccessPolicy.Builder()
- .identifier(policyIdentifier.toString())
- .resource(resource)
- .addUser(identity);
-
- if (action.equals(READ_CODE)) {
- builder.action(RequestAction.READ);
- } else if (action.equals(WRITE_CODE)) {
- builder.action(RequestAction.WRITE);
- } else {
- throw new IllegalStateException("Unknown Policy Action: " + action);
+ // first try to find an existing policy for the given resource and action
+ Policy foundPolicy = null;
+ for (Policy policy : authorizations.getPolicies().getPolicy()) {
+ if (policy.getResource().equals(resource) && policy.getAction().equals(action)) {
+ foundPolicy = policy;
+ break;
+ }
}
- final AccessPolicy accessPolicy = builder.build();
- final Policy jaxbPolicy = createJAXBPolicy(accessPolicy);
- authorizations.getPolicies().getPolicy().add(jaxbPolicy);
+ if (foundPolicy == null) {
+ // if we didn't find an existing policy create a new one
+ final String uuidSeed = resource + identity + action;
+ final UUID policyIdentifier = UUID.nameUUIDFromBytes(uuidSeed.getBytes(StandardCharsets.UTF_8));
+
+ final AccessPolicy.Builder builder = new AccessPolicy.Builder()
+ .identifier(policyIdentifier.toString())
+ .resource(resource)
+ .addUser(identity);
+
+ if (action.equals(READ_CODE)) {
+ builder.action(RequestAction.READ);
+ } else if (action.equals(WRITE_CODE)) {
+ builder.action(RequestAction.WRITE);
+ } else {
+ throw new IllegalStateException("Unknown Policy Action: " + action);
+ }
+
+ final AccessPolicy accessPolicy = builder.build();
+ final Policy jaxbPolicy = createJAXBPolicy(accessPolicy);
+ authorizations.getPolicies().getPolicy().add(jaxbPolicy);
+ } else {
+ // otherwise add the user to the existing policy
+ Policy.User policyUser = new Policy.User();
+ policyUser.setIdentifier(identity);
+ foundPolicy.getUser().add(policyUser);
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
index efe078f..1eed4e6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/java/org/apache/nifi/authorization/FileAuthorizerTest.java
@@ -157,10 +157,12 @@ public class FileAuthorizerTest {
assertEquals(1, users.size());
UsersAndAccessPolicies usersAndAccessPolicies = authorizer.getUsersAndAccessPolicies();
- assertEquals(1, usersAndAccessPolicies.getAccessPolicies(ResourceType.Flow.getValue()).size());
- assertEquals(2, usersAndAccessPolicies.getAccessPolicies(ResourceType.Controller.getValue()).size());
- assertEquals(1, usersAndAccessPolicies.getAccessPolicies(ResourceType.System.getValue()).size());
- assertEquals(2, usersAndAccessPolicies.getAccessPolicies(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID).size());
+ assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.Flow.getValue(), RequestAction.READ));
+ assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.Controller.getValue(), RequestAction.READ));
+ assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.Controller.getValue(), RequestAction.WRITE));
+ assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.System.getValue(), RequestAction.READ));
+ assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.READ));
+ assertNotNull(usersAndAccessPolicies.getAccessPolicy(ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID, RequestAction.WRITE));
}
@Test
@@ -340,7 +342,7 @@ public class FileAuthorizerTest {
assertEquals(adminIdentity, adminUser.getIdentity());
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
- assertEquals(4, policies.size());
+ assertEquals(7, policies.size());
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
@@ -377,7 +379,7 @@ public class FileAuthorizerTest {
assertEquals(adminIdentity, adminUser.getIdentity());
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
- assertEquals(3, policies.size());
+ assertEquals(5, policies.size());
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
@@ -414,7 +416,7 @@ public class FileAuthorizerTest {
assertEquals(adminIdentity, adminUser.getIdentity());
final Set<AccessPolicy> policies = authorizer.getAccessPolicies();
- assertEquals(3, policies.size());
+ assertEquals(5, policies.size());
final String rootGroupResource = ResourceType.ProcessGroup.getValue() + "/" + ROOT_GROUP_ID;
@@ -430,6 +432,46 @@ public class FileAuthorizerTest {
}
@Test
+ public void testOnConfiguredWhenNodeIdentitiesProvided() throws Exception {
+ final String adminIdentity = "admin-user";
+
+ when(configurationContext.getProperty(Mockito.eq(FileAuthorizer.PROP_INITIAL_ADMIN_IDENTITY)))
+ .thenReturn(new StandardPropertyValue(adminIdentity, null));
+
+ final String nodeIdentity1 = "node1";
+ final String nodeIdentity2 = "node2";
+
+ final Map<String,String> props = new HashMap<>();
+ props.put("Node Identity 1", nodeIdentity1);
+ props.put("Node Identity 2", nodeIdentity2);
+
+ when(configurationContext.getProperties()).thenReturn(props);
+
+ writeAuthorizationsFile(primary, EMPTY_AUTHORIZATIONS_CONCISE);
+ authorizer.onConfigured(configurationContext);
+
+ User adminUser = authorizer.getUserByIdentity(adminIdentity);
+ assertNotNull(adminUser);
+
+ User nodeUser1 = authorizer.getUserByIdentity(nodeIdentity1);
+ assertNotNull(nodeUser1);
+
+ User nodeUser2 = authorizer.getUserByIdentity(nodeIdentity2);
+ assertNotNull(nodeUser2);
+
+ AccessPolicy proxyReadPolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(ResourceType.Proxy.getValue(), RequestAction.READ);
+ AccessPolicy proxyWritePolicy = authorizer.getUsersAndAccessPolicies().getAccessPolicy(ResourceType.Proxy.getValue(), RequestAction.WRITE);
+
+ assertNotNull(proxyReadPolicy);
+ assertTrue(proxyReadPolicy.getUsers().contains(nodeUser1.getIdentifier()));
+ assertTrue(proxyReadPolicy.getUsers().contains(nodeUser2.getIdentifier()));
+
+ assertNotNull(proxyWritePolicy);
+ assertTrue(proxyWritePolicy.getUsers().contains(nodeUser1.getIdentifier()));
+ assertTrue(proxyWritePolicy.getUsers().contains(nodeUser2.getIdentifier()));
+ }
+
+ @Test
public void testOnConfiguredWhenAuthorizationsFileDoesNotExist() {
authorizer.onConfigured(configurationContext);
assertEquals(0, authorizer.getAccessPolicies().size());
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
index 8d50151..372d89f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/StandardNiFiUser.java
@@ -27,14 +27,24 @@ public class StandardNiFiUser implements NiFiUser {
private final String identity;
private final NiFiUser chain;
+ private final String clientAddress;
public StandardNiFiUser(String identity) {
- this(identity, null);
+ this(identity, null, null);
+ }
+
+ public StandardNiFiUser(String identity, String clientAddress) {
+ this(identity, null, clientAddress);
}
public StandardNiFiUser(String identity, NiFiUser chain) {
+ this(identity, chain, null);
+ }
+
+ public StandardNiFiUser(String identity, NiFiUser chain, String clientAddress) {
this.identity = identity;
this.chain = chain;
+ this.clientAddress = clientAddress;
}
@@ -54,6 +64,11 @@ public class StandardNiFiUser implements NiFiUser {
}
@Override
+ public String getClientAddress() {
+ return clientAddress;
+ }
+
+ @Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
index 5231095..ecc9e6f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/Template.java
@@ -16,6 +16,7 @@
*/
package org.apache.nifi.controller;
+import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.AccessDeniedException;
import org.apache.nifi.authorization.AuthorizationRequest;
import org.apache.nifi.authorization.AuthorizationResult;
@@ -23,6 +24,7 @@ import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.resource.ResourceType;
@@ -41,7 +43,9 @@ import org.apache.nifi.web.api.dto.ProcessorDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
public class Template implements Authorizable {
@@ -168,7 +172,13 @@ public class Template implements Authorizable {
}
private AuthorizationResult checkAuthorization(final Authorizer authorizer, final RequestAction action, final boolean accessAttempt, final NiFiUser user) {
- // TODO - include user details context
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
// build the request
final AuthorizationRequest request = new AuthorizationRequest.Builder()
@@ -177,6 +187,7 @@ public class Template implements Authorizable {
.accessAttempt(accessAttempt)
.action(action)
.resource(getResource())
+ .userContext(userContext)
.build();
// perform the authorization
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizations.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizations.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizations.xml
index 6403d95..a4aa839 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizations.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizations.xml
@@ -14,59 +14,10 @@
limitations under the License.
-->
<!--
- This file lists all authorizations for this NiFi instance. Refer to the properties file and authorizers.xml for configuration details.
-
- Available resources:
- /flow - READ - allows user/entity to load the UI and see the flow structure
- - WRITE - NA
- /resource - READ - allows user/entity to retrieve the available resources
- - WRITE - NA
- /system - READ - allows user/entity to retrieve system level diagnostics (CPU load, disk utilization, etc)
- - WRITE - NA
- /controller - READ - allows user/entity to retrieve configuration details for the controller (controller bulletins, thread pool, reporting tasks, etc)
- - WRITE - allows user/entity to modify configuration details for the controller
- /provenance - READ - allows user/entity to perform provenance requests. results will be filtered based on access to provenance data per component
- - WRITE - NA
- /token - READ - NA
- - WRITE - allows user/entity to create a token for access the REST API
- /site-to-site - READ - allows user/entity to retrieve configuration details for performing site to site data transfers with this NiFi
- - WRITE - NA
- /proxy - READ - NA
- - WRITE - allows user/entity to create a proxy request on behalf of another user
- /process-groups/{id} - READ - allows user/entity to retrieve configuration details for the process group and all descendant components without explicit access policies
- - WRITE - allows user/entity to create/update/delete configuration details for the process group and all descendant components without explicit access policies
- /processors/{id} - READ - allows user/entity to retrieve configuration details for the processor overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the processor overriding any inherited authorizations from an ancestor process group
- /input-ports/{id} - READ - allows user/entity to retrieve configuration details for the input port overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the input port overriding any inherited authorizations from an ancestor process group
- /output-ports/{id} - READ - allows user/entity to retrieve configuration details for the output port overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the output port overriding any inherited authorizations from an ancestor process group
- /labels/{id} - READ - allows user/entity to retrieve configuration details for the label overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the label overriding any inherited authorizations from an ancestor process group
- /connections/{id} - READ - allows user/entity to retrieve configuration details for the connection overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the label overriding any inherited authorizations from an ancestor process group
- /remote-process-groups/{id} - READ - allows user/entity to retrieve configuration details for the remote process group overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the remote process group overriding any inherited authorizations from an ancestor process group
- /templates/{id} - READ - allows user/entity to retrieve configuration details for the template overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to create/update/delete the template overriding any inherited authorizations from an ancestor process group
- /controller-services/{id} - READ - allows user/entity to retrieve configuration details for the controller service overriding any inherited authorizations from an ancestor process group
- - WRITE - allows user/entity to update/delete the controller service overriding any inherited authorizations from an ancestor process group
- /reporting-tasks/{id} - READ - allows user/entity to retrieve configuration details for the reporting tasks overriding any inherited authorizations from the controller
- - WRITE - allows user/entity to create/update/delete the reporting tasks overriding any inherited authorizations from the controller
- /{type}/{id}/provenance - READ - allows user/entity to view provenance data from the underlying component
- - WRITE - NA
+ This file should not be manually edited. Authorizations should only be created through the NiFi UI, and during
+ initial setup of a new instance. Refer to authorizers.xml for properties that allow seeding a new installation
+ with initial authorizations.
-->
<authorizations>
- <!--
- <users>
- <user identifier="1" identity="" />
- </users>
-
- <policies>
- <policy identifier="1" resource="/flow" action="RW">
- <user identifier="1" />
- </policy>
- </policies>
- -->
</authorizations>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
index 12efb79..aa47a14 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/authorizers.xml
@@ -19,11 +19,34 @@
must be specified in the nifi.properties file.
-->
<authorizers>
+
+ <!--
+ The FileAuthorizer is NiFi's provided authorizer and has the following properties:
+
+ - Authorizations File - The file where the FileAuthorizer will store authorizations.
+
+ - Initial Admin Identity - The identity of an initial admin user that will be granted access to the UI and
+ given the ability to create additional users, groups, and policies. The value of this property could be
+ a DN when using certificates or LDAP, or a Kerberos principal. This property will only be used when there
+ are no other users, groups, and policies defined. If this property is specified then a Legacy Authorized
+ Users File can not be specified.
+
+ - Legacy Authorized Users File - The full path to an existing authorized-users.xml that will be automatically
+ converted to the new authorizations model. If this property is specified then an Initial Admin Identity can
+ not be specified, and this property will only be used when there are no other users, groups, and policies defined.
+
+ - Node Identity [unique key] - The identity of a NiFi cluster node. When clustered, a property for each node
+ should be defined, so that every node knows about every other node. If not clustered these properties can be ignored.
+ -->
<authorizer>
<identifier>file-provider</identifier>
<class>org.apache.nifi.authorization.FileAuthorizer</class>
<property name="Authorizations File">./conf/authorizations.xml</property>
<property name="Initial Admin Identity"></property>
<property name="Legacy Authorized Users File"></property>
+ <!--
+ <property name="Node Identity 1"></property>
+ <property name="Node Identity 2"></property>
+ -->
</authorizer>
</authorizers>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
index dfbc6fd..cc69489 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
@@ -144,6 +144,16 @@ nifi.security.user.login.identity.provider=${nifi.security.user.login.identity.p
nifi.security.ocsp.responder.url=${nifi.security.ocsp.responder.url}
nifi.security.ocsp.responder.certificate=${nifi.security.ocsp.responder.certificate}
+# Identity Mapping Properties #
+# These properties allow normalizing user identities such that identities coming from different identity providers
+# (certificates, LDAP, Kerberos) can be treated the same internally in NiFi. The following example demonstrates normalizing
+# DNs from certificates and principals from Kerberos into a common identity string:
+#
+# nifi.security.identity.mapping.pattern.dn=^CN=(.*?), OU=(.*?), O=(.*?), L=(.*?), ST=(.*?), C=(.*?)$
+# nifi.security.identity.mapping.value.dn=$1@$2
+# nifi.security.identity.mapping.pattern.kerb=^(.*?)/instance@(.*?)$
+# nifi.security.identity.mapping.value.kerb=$1@$2
+
# cluster common properties (all nodes must have same values) #
nifi.cluster.protocol.heartbeat.interval=${nifi.cluster.protocol.heartbeat.interval}
nifi.cluster.protocol.is.secure=${nifi.cluster.protocol.is.secure}
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
index e340623..641ed38 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
@@ -48,6 +48,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
@@ -97,12 +98,21 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
private void authorizeFlowAccess(final NiFiUser user) {
// authorize access
serviceFacade.authorizeAccess(lookup -> {
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getFlowResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
index e0162bc..6f79a23 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
@@ -34,6 +34,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserDetails;
@@ -77,6 +78,8 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
@@ -108,12 +111,21 @@ public class AccessResource extends ApplicationResource {
* Authorizes access to the flow.
*/
private boolean hasFlowAccess(final NiFiUser user) {
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getFlowResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
@@ -198,7 +210,7 @@ public class AccessResource extends ApplicationResource {
// Extract the Base64 encoded token from the Authorization header
final String token = StringUtils.substringAfterLast(authorization, " ");
- final JwtAuthenticationRequestToken jwtRequest = new JwtAuthenticationRequestToken(token);
+ final JwtAuthenticationRequestToken jwtRequest = new JwtAuthenticationRequestToken(token, httpServletRequest.getRemoteAddr());
final NiFiAuthenticationToken authenticationResponse = (NiFiAuthenticationToken) jwtAuthenticationProvider.authenticate(jwtRequest);
final NiFiUser nifiUser = ((NiFiUserDetails) authenticationResponse.getDetails()).getNiFiUser();
@@ -215,7 +227,7 @@ public class AccessResource extends ApplicationResource {
} else {
try {
final X509AuthenticationRequestToken x509Request = new X509AuthenticationRequestToken(
- httpServletRequest.getHeader(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN), principalExtractor, certificates);
+ httpServletRequest.getHeader(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN), principalExtractor, certificates, httpServletRequest.getRemoteAddr());
final NiFiAuthenticationToken authenticationResponse = (NiFiAuthenticationToken) x509AuthenticationProvider.authenticate(x509Request);
final NiFiUser nifiUser = ((NiFiUserDetails) authenticationResponse.getDetails()).getNiFiUser();
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index 31ecd4c..836d254 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -30,6 +30,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -66,6 +67,8 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
/**
* RESTful endpoint for managing a Flow Controller.
@@ -92,12 +95,21 @@ public class ControllerResource extends ApplicationResource {
private void authorizeController(final RequestAction action) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getControllerResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/CountersResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/CountersResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/CountersResource.java
index fea5d30..48d34e1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/CountersResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/CountersResource.java
@@ -17,6 +17,8 @@
package org.apache.nifi.web.api;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
@@ -40,6 +42,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -84,12 +87,21 @@ public class CountersResource extends ApplicationResource {
private void authorizeCounters(final RequestAction action) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getCountersResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
index 961984b..4447014 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
@@ -49,6 +49,7 @@ import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
@@ -210,12 +211,21 @@ public class FlowResource extends ApplicationResource {
private void authorizeFlow(final RequestAction action) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getFlowResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
@@ -228,12 +238,21 @@ public class FlowResource extends ApplicationResource {
private boolean isAuthorized(final RequestAction action, final Resource resource) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(false)
.action(action)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
index 70339ea..9fa2871 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProvenanceResource.java
@@ -29,6 +29,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -92,12 +93,21 @@ public class ProvenanceResource extends ApplicationResource {
private void authorizeProvenanceRequest() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getProvenanceResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
index 2df4db7..83f313f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ResourceResource.java
@@ -16,7 +16,9 @@
*/
package org.apache.nifi.web.api;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -33,6 +35,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -62,12 +65,21 @@ public class ResourceResource extends ApplicationResource {
private void authorizeResource() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getResourceResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
index 429fb4b..ef5c961 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
@@ -17,6 +17,8 @@
package org.apache.nifi.web.api;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
import javax.ws.rs.Consumes;
@@ -36,6 +38,7 @@ import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
@@ -68,12 +71,21 @@ public class SystemDiagnosticsResource extends ApplicationResource {
private void authorizeSystem() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getSystemResource())
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
+ .userContext(userContext)
.build();
final AuthorizationResult result = authorizer.authorize(request);
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
index 2c6d948..b7472fc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
@@ -1210,7 +1210,8 @@ public class ControllerFacade implements Authorizable {
final List<String> dnChain = ProxiedEntitiesUtils.buildProxiedEntitiesChain(user);
for (final String identity : dnChain) {
final Authorizable eventAuthorizable = flowController.createProvenanceAuthorizable(componentId);
- final NiFiUser chainUser = new StandardNiFiUser(identity) {
+ final String clientAddress = user.getIdentity().equals(identity) ? user.getClientAddress() : null;
+ final NiFiUser chainUser = new StandardNiFiUser(identity, clientAddress) {
@Override
public boolean isAnonymous() {
// allow current user to drive anonymous flag as anonymous users are never chained... supports single user case
@@ -1243,7 +1244,8 @@ public class ControllerFacade implements Authorizable {
final List<String> dnChain = ProxiedEntitiesUtils.buildProxiedEntitiesChain(user);
for (final String identity : dnChain) {
final Authorizable eventAuthorizable = flowController.createProvenanceAuthorizable(componentId);
- final NiFiUser chainUser = new StandardNiFiUser(identity) {
+ final String clientAddress = user.getIdentity().equals(identity) ? user.getClientAddress() : null;
+ final NiFiUser chainUser = new StandardNiFiUser(identity, clientAddress) {
@Override
public boolean isAnonymous() {
// allow current user to drive anonymous flag as anonymous users are never chained... supports single user case
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
index 1ac13ce..0aff212 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
@@ -16,12 +16,14 @@
*/
package org.apache.nifi.web.dao.impl;
+import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authorization.AccessDeniedException;
import org.apache.nifi.authorization.AuthorizationRequest;
import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.connectable.Connectable;
@@ -57,6 +59,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -598,6 +601,14 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
final List<String> dnChain = ProxiedEntitiesUtils.buildProxiedEntitiesChain(user);
dnChain.forEach(identity -> {
// build the request
+ final Map<String,String> userContext;
+ if (!StringUtils.isBlank(user.getClientAddress())) {
+ userContext = new HashMap<>();
+ userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
+ } else {
+ userContext = null;
+ }
+
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity(identity)
.anonymous(user.isAnonymous())
@@ -605,6 +616,7 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
.action(RequestAction.WRITE)
.resource(connection.getResource())
.resourceContext(attributes)
+ .userContext(userContext)
.build();
// perform the authorization
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
new file mode 100644
index 0000000..f3f6bd0
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationProvider.java
@@ -0,0 +1,185 @@
+/*
+ * 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.web.security;
+
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AuthenticationProvider;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Base AuthenticationProvider that provides common functionality to mapping identities.
+ */
+public abstract class NiFiAuthenticationProvider implements AuthenticationProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NiFiAuthenticationProvider.class);
+ private static final Pattern backReferencePattern = Pattern.compile("\\$(\\d+)");
+
+ private NiFiProperties properties;
+ private List<IdentityMapping> mappings;
+
+ /**
+ * @param properties the NiFiProperties instance
+ */
+ public NiFiAuthenticationProvider(final NiFiProperties properties) {
+ this.properties = properties;
+ this.mappings = Collections.unmodifiableList(getIdentityMappings(properties));
+ }
+
+ /**
+ * Builds the identity mappings from NiFiProperties.
+ *
+ * @param properties the NiFiProperties instance
+ * @return a list of identity mappings
+ */
+ private List<IdentityMapping> getIdentityMappings(final NiFiProperties properties) {
+ final List<IdentityMapping> mappings = new ArrayList<>();
+
+ // go through each property
+ for (String propertyName : properties.stringPropertyNames()) {
+ if (StringUtils.startsWith(propertyName, NiFiProperties.SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX)) {
+ final String key = StringUtils.substringAfter(propertyName, NiFiProperties.SECURITY_IDENTITY_MAPPING_PATTERN_PREFIX);
+ final String identityPattern = properties.getProperty(propertyName);
+
+ if (StringUtils.isBlank(identityPattern)) {
+ LOGGER.warn("Identity Mapping property {} was found, but was empty", new Object[]{propertyName});
+ continue;
+ }
+
+ final String identityValueProperty = NiFiProperties.SECURITY_IDENTITY_MAPPING_VALUE_PREFIX + key;
+ final String identityValue = properties.getProperty(identityValueProperty);
+
+ if (StringUtils.isBlank(identityValue)) {
+ LOGGER.warn("Identity Mapping property {} was found, but corresponding value {} was not found",
+ new Object[]{propertyName, identityValueProperty});
+ continue;
+ }
+
+ final IdentityMapping identityMapping = new IdentityMapping(key, Pattern.compile(identityPattern), identityValue);
+ mappings.add(identityMapping);
+
+ LOGGER.debug("Found Identity Mapping with key = {}, pattern = {}, value = {}",
+ new Object[] {key, identityPattern, identityValue});
+ }
+ }
+
+ // sort the list by the key so users can control the ordering in nifi.properties
+ Collections.sort(mappings, new Comparator<IdentityMapping>() {
+ @Override
+ public int compare(IdentityMapping m1, IdentityMapping m2) {
+ return m1.getKey().compareTo(m2.getKey());
+ }
+ });
+
+ return mappings;
+ }
+
+ public List<IdentityMapping> getMappings() {
+ return mappings;
+ }
+
+ protected String mapIdentity(final String identity) {
+ for (IdentityMapping mapping : mappings) {
+ Matcher m = mapping.getPattern().matcher(identity);
+ if (m.matches()) {
+ final String pattern = mapping.getPattern().pattern();
+ final String replacementValue = escapeLiteralBackReferences(mapping.getReplacementValue(), m.groupCount());
+ return identity.replaceAll(pattern, replacementValue);
+ }
+ }
+
+ return identity;
+ }
+
+ // If we find a back reference that is not valid, then we will treat it as a literal string. For example, if we have 3 capturing
+ // groups and the Replacement Value has the value is "I owe $8 to him", then we want to treat the $8 as a literal "$8", rather
+ // than attempting to use it as a back reference.
+ private static String escapeLiteralBackReferences(final String unescaped, final int numCapturingGroups) {
+ if (numCapturingGroups == 0) {
+ return unescaped;
+ }
+
+ String value = unescaped;
+ final Matcher backRefMatcher = backReferencePattern.matcher(value);
+ while (backRefMatcher.find()) {
+ final String backRefNum = backRefMatcher.group(1);
+ if (backRefNum.startsWith("0")) {
+ continue;
+ }
+ final int originalBackRefIndex = Integer.parseInt(backRefNum);
+ int backRefIndex = originalBackRefIndex;
+
+ // if we have a replacement value like $123, and we have less than 123 capturing groups, then
+ // we want to truncate the 3 and use capturing group 12; if we have less than 12 capturing groups,
+ // then we want to truncate the 2 and use capturing group 1; if we don't have a capturing group then
+ // we want to truncate the 1 and get 0.
+ while (backRefIndex > numCapturingGroups && backRefIndex >= 10) {
+ backRefIndex /= 10;
+ }
+
+ if (backRefIndex > numCapturingGroups) {
+ final StringBuilder sb = new StringBuilder(value.length() + 1);
+ final int groupStart = backRefMatcher.start(1);
+
+ sb.append(value.substring(0, groupStart - 1));
+ sb.append("\\");
+ sb.append(value.substring(groupStart - 1));
+ value = sb.toString();
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Holder to pass around the key, pattern, and replacement from an identity mapping in NiFiProperties.
+ */
+ public static final class IdentityMapping {
+
+ private final String key;
+ private final Pattern pattern;
+ private final String replacementValue;
+
+ public IdentityMapping(String key, Pattern pattern, String replacementValue) {
+ this.key = key;
+ this.pattern = pattern;
+ this.replacementValue = replacementValue;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Pattern getPattern() {
+ return pattern;
+ }
+
+ public String getReplacementValue() {
+ return replacementValue;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/ba763b95/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationRequestToken.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationRequestToken.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationRequestToken.java
new file mode 100644
index 0000000..21397b6
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationRequestToken.java
@@ -0,0 +1,41 @@
+/*
+ * 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.web.security;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+
+/**
+ * Base class for authentication request tokens in NiFI.
+ */
+public abstract class NiFiAuthenticationRequestToken extends AbstractAuthenticationToken {
+
+ private final String clientAddress;
+
+ /**
+ * @param clientAddress The address of the client making the request
+ */
+ public NiFiAuthenticationRequestToken(final String clientAddress) {
+ super(null);
+ setAuthenticated(false);
+ this.clientAddress = clientAddress;
+ }
+
+ public String getClientAddress() {
+ return clientAddress;
+ }
+
+}