You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ym...@apache.org on 2017/07/24 19:52:59 UTC
[2/3] nifi git commit: NIFI-4032: - Introducing the
ManagedRangerAuthorizer. - Introducing the AuthorizationAuditor. - Updating
authorization requests to utilize Authorizable where ever possible so allow
for a singular place to audit resource not found a
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/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 c17ad85..55ed489 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
@@ -22,16 +22,9 @@ import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
-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.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.api.dto.provenance.ProvenanceDTO;
@@ -101,31 +94,10 @@ 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())
- .groups(user.getGroups())
- .anonymous(user.isAnonymous())
- .accessAttempt(true)
- .action(RequestAction.READ)
- .userContext(userContext)
- .explanationSupplier(() -> "Unable to query provenance.")
- .build();
-
- final AuthorizationResult result = authorizer.authorize(request);
- if (!Result.Approved.equals(result.getResult())) {
- throw new AccessDeniedException(result.getExplanation());
- }
+ serviceFacade.authorizeAccess(lookup -> {
+ final Authorizable provenance = lookup.getProvenance();
+ provenance.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+ });
}
/**
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/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 1c91e5e..f957302 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
@@ -21,16 +21,9 @@ import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
-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.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.web.NiFiServiceFacade;
import org.apache.nifi.web.api.dto.ResourceDTO;
@@ -43,9 +36,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* RESTful endpoint for retrieving system diagnostics.
@@ -61,31 +52,10 @@ public class ResourceResource extends ApplicationResource {
private Authorizer authorizer;
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())
- .groups(user.getGroups())
- .anonymous(user.isAnonymous())
- .accessAttempt(true)
- .action(RequestAction.READ)
- .userContext(userContext)
- .explanationSupplier(() -> "Unable to retrieve resources.")
- .build();
-
- final AuthorizationResult result = authorizer.authorize(request);
- if (!Result.Approved.equals(result.getResult())) {
- throw new AccessDeniedException(result.getExplanation());
- }
+ serviceFacade.authorizeAccess(lookup -> {
+ final Authorizable resource = lookup.getResource();
+ resource.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+ });
}
/**
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.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/SiteToSiteResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.java
index fc6d4dd..2e17637 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SiteToSiteResource.java
@@ -22,16 +22,9 @@ import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
-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.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.node.NodeWorkload;
@@ -63,7 +56,6 @@ import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -99,31 +91,10 @@ public class SiteToSiteResource extends ApplicationResource {
* Note: Protected for testing purposes
*/
protected void authorizeSiteToSite() {
- 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.getSiteToSiteResource())
- .identity(user.getIdentity())
- .groups(user.getGroups())
- .anonymous(user.isAnonymous())
- .accessAttempt(true)
- .action(RequestAction.READ)
- .userContext(userContext)
- .explanationSupplier(() -> "Unable to retrieve site to site details.")
- .build();
-
- final AuthorizationResult result = authorizer.authorize(request);
- if (!Result.Approved.equals(result.getResult())) {
- throw new AccessDeniedException(result.getExplanation());
- }
+ serviceFacade.authorizeAccess(lookup -> {
+ final Authorizable siteToSite = lookup.getSiteToSite();
+ siteToSite.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+ });
}
/**
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/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 063f96c..ff69e60 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
@@ -22,16 +22,9 @@ import com.wordnik.swagger.annotations.ApiParam;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;
import com.wordnik.swagger.annotations.Authorization;
-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.resource.ResourceFactory;
-import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.cluster.manager.NodeResponse;
import org.apache.nifi.web.NiFiServiceFacade;
@@ -47,8 +40,6 @@ import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import java.util.HashMap;
-import java.util.Map;
/**
* RESTful endpoint for retrieving system diagnostics.
@@ -64,31 +55,10 @@ public class SystemDiagnosticsResource extends ApplicationResource {
private Authorizer authorizer;
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())
- .groups(user.getGroups())
- .anonymous(user.isAnonymous())
- .accessAttempt(true)
- .action(RequestAction.READ)
- .userContext(userContext)
- .explanationSupplier(() -> "Unable to view system diagnostics.")
- .build();
-
- final AuthorizationResult result = authorizer.authorize(request);
- if (!Result.Approved.equals(result.getResult())) {
- throw new AccessDeniedException(result.getExplanation());
- }
+ serviceFacade.authorizeAccess(lookup -> {
+ final Authorizable system = lookup.getSystem();
+ system.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+ });
}
/**
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
index 556c6bc..ce8f18a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
@@ -84,6 +84,7 @@ public class NiFiWebApiTest {
processorEntity = response.getEntity(ProcessorEntity.class);
processorDTO = processorEntity.getComponent();
String localSelectionId = processorDTO.getId();
+ String localSelectionGroupId = processorDTO.getParentGroupId();
// -----------------------------------------------
// Create a termination processor
@@ -114,6 +115,7 @@ public class NiFiWebApiTest {
processorEntity = response.getEntity(ProcessorEntity.class);
processorDTO = processorEntity.getComponent();
String terminationId = processorDTO.getId();
+ String terminationGroupId = processorDTO.getParentGroupId();
// -----------------------------------------------
// Connect the two processors
@@ -121,10 +123,12 @@ public class NiFiWebApiTest {
ConnectableDTO source = new ConnectableDTO();
source.setId(localSelectionId);
+ source.setGroupId(localSelectionGroupId);
source.setType(ConnectableType.PROCESSOR.name());
ConnectableDTO target = new ConnectableDTO();
target.setId(terminationId);
+ target.setGroupId(terminationGroupId);
target.setType(ConnectableType.PROCESSOR.name());
// create the relationships
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
index dcc00d9..bb2d4eb 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ITConnectionAccessControl.java
@@ -358,11 +358,13 @@ public class ITConnectionAccessControl {
// create the source connectable
ConnectableDTO source = new ConnectableDTO();
source.setId(one.getId());
+ source.setGroupId(one.getComponent().getParentGroupId());
source.setType(ConnectableType.PROCESSOR.name());
// create the target connectable
ConnectableDTO target = new ConnectableDTO();
target.setId(two.getId());
+ target.setGroupId(two.getComponent().getParentGroupId());
target.setType(ConnectableType.PROCESSOR.name());
// create the relationships
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/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
index 5636c2d..ec162c7 100644
--- 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
@@ -46,6 +46,7 @@ public abstract class NiFiAuthenticationProvider implements AuthenticationProvid
public NiFiAuthenticationProvider(final NiFiProperties properties, final Authorizer authorizer) {
this.properties = properties;
this.mappings = Collections.unmodifiableList(IdentityMappingUtil.getIdentityMappings(properties));
+ this.authorizer = authorizer;
}
public List<IdentityMapping> getMappings() {
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.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/x509/X509AuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
index 510e136..564171f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
@@ -18,12 +18,12 @@ package org.apache.nifi.web.security.x509;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.authentication.AuthenticationResponse;
-import org.apache.nifi.authorization.AuthorizationRequest;
-import org.apache.nifi.authorization.AuthorizationResult;
-import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.AccessDeniedException;
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;
import org.apache.nifi.authorization.user.NiFiUserDetails;
@@ -50,6 +50,18 @@ import java.util.Set;
*/
public class X509AuthenticationProvider extends NiFiAuthenticationProvider {
+ private static final Authorizable PROXY_AUTHORIZABLE = new Authorizable() {
+ @Override
+ public Authorizable getParentAuthorizable() {
+ return null;
+ }
+
+ @Override
+ public Resource getResource() {
+ return ResourceFactory.getProxyResource();
+ }
+ };
+
private X509IdentityProvider certificateIdentityProvider;
private Authorizer authorizer;
@@ -94,27 +106,17 @@ public class X509AuthenticationProvider extends NiFiAuthenticationProvider {
final Set<String> groups = getUserGroups(identity);
+ // Only set the client address for client making the request because we don't know the clientAddress of the proxied entities
+ String clientAddress = (proxy == null) ? request.getClientAddress() : null;
+ proxy = createUser(identity, groups, proxy, clientAddress, isAnonymous);
+
if (chainIter.hasPrevious()) {
- // authorize this proxy in order to authenticate this user
- final AuthorizationRequest proxyAuthorizationRequest = new AuthorizationRequest.Builder()
- .identity(identity)
- .groups(groups)
- .anonymous(isAnonymous)
- .accessAttempt(true)
- .action(RequestAction.WRITE)
- .resource(ResourceFactory.getProxyResource())
- .userContext(proxy == null ? getUserContext(request) : null) // only set the context for the real user
- .build();
-
- final AuthorizationResult proxyAuthorizationResult = authorizer.authorize(proxyAuthorizationRequest);
- if (!Result.Approved.equals(proxyAuthorizationResult.getResult())) {
+ try {
+ PROXY_AUTHORIZABLE.authorize(authorizer, RequestAction.WRITE, proxy);
+ } catch (final AccessDeniedException e) {
throw new UntrustedProxyException(String.format("Untrusted proxy %s", identity));
}
}
-
- // Only set the client address for user making the request because we don't know the client address of the proxies
- String clientAddress = (proxy == null) ? request.getClientAddress() : null;
- proxy = createUser(identity, groups, proxy, clientAddress, isAnonymous);
}
return new NiFiAuthenticationToken(new NiFiUserDetails(proxy));
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
new file mode 100644
index 0000000..7c16a80
--- /dev/null
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
@@ -0,0 +1,205 @@
+/*
+ * 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.ranger.authorization;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.nifi.authorization.AccessPolicy;
+import org.apache.nifi.authorization.AccessPolicyProvider;
+import org.apache.nifi.authorization.AccessPolicyProviderInitializationContext;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.ConfigurableUserGroupProvider;
+import org.apache.nifi.authorization.ManagedAuthorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.UserGroupProvider;
+import org.apache.nifi.authorization.UserGroupProviderLookup;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.Set;
+
+public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements ManagedAuthorizer {
+
+ private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
+
+ private static final String USER_GROUP_PROVIDER_ELEMENT = "userGroupProvider";
+
+ private UserGroupProviderLookup userGroupProviderLookup;
+ private UserGroupProvider userGroupProvider;
+ private RangerBasePluginWithPolicies nifiPlugin;
+
+ @Override
+ public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
+ userGroupProviderLookup = initializationContext.getUserGroupProviderLookup();
+
+ super.initialize(initializationContext);
+ }
+
+ @Override
+ public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+ final String userGroupProviderKey = configurationContext.getProperty("User Group Provider").getValue();
+ userGroupProvider = userGroupProviderLookup.getUserGroupProvider(userGroupProviderKey);
+
+ // ensure the desired access policy provider has a user group provider
+ if (userGroupProvider == null) {
+ throw new AuthorizerCreationException(String.format("Unable to locate configured User Group Provider: %s", userGroupProviderKey));
+ }
+
+ super.onConfigured(configurationContext);
+ }
+
+ @Override
+ protected RangerBasePluginWithPolicies createRangerBasePlugin(final String serviceType, final String appId) {
+ // override the method for creating the ranger base plugin so a user group provider can be specified
+ nifiPlugin = new RangerBasePluginWithPolicies(serviceType, appId, userGroupProvider);
+ return nifiPlugin;
+ }
+
+ @Override
+ public AccessPolicyProvider getAccessPolicyProvider() {
+ return new AccessPolicyProvider() {
+ @Override
+ public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+ return nifiPlugin.getAccessPolicies();
+ }
+
+ @Override
+ public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+ return nifiPlugin.getAccessPolicy(identifier);
+ }
+
+ @Override
+ public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+ return nifiPlugin.getAccessPolicy(resourceIdentifier, action);
+ }
+
+ @Override
+ public UserGroupProvider getUserGroupProvider() {
+ return userGroupProvider;
+ }
+
+ @Override
+ public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
+ }
+
+ @Override
+ public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+ }
+
+ @Override
+ public void preDestruction() throws AuthorizerDestructionException {
+ }
+ };
+ }
+
+ @Override
+ public String getFingerprint() throws AuthorizationAccessException {
+ final StringWriter out = new StringWriter();
+ try {
+ // create the document
+ final DocumentBuilder documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+ final Document document = documentBuilder.newDocument();
+
+ // create the root element
+ final Element managedRangerAuthorizationsElement = document.createElement("managedRangerAuthorizations");
+ document.appendChild(managedRangerAuthorizationsElement);
+
+ // create the user group provider element
+ final Element userGroupProviderElement = document.createElement(USER_GROUP_PROVIDER_ELEMENT);
+ managedRangerAuthorizationsElement.appendChild(userGroupProviderElement);
+
+ // append fingerprint if the provider is configurable
+ if (userGroupProvider instanceof ConfigurableUserGroupProvider) {
+ userGroupProviderElement.appendChild(document.createTextNode(((ConfigurableUserGroupProvider) userGroupProvider).getFingerprint()));
+ }
+
+ final Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.transform(new DOMSource(document), new StreamResult(out));
+ } catch (ParserConfigurationException | TransformerException e) {
+ throw new AuthorizationAccessException("Unable to generate fingerprint", e);
+ }
+
+ return out.toString();
+ }
+
+ @Override
+ public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
+ if (StringUtils.isBlank(fingerprint)) {
+ return;
+ }
+
+ final String userGroupFingerprint = parseFingerprint(fingerprint);
+
+ if (StringUtils.isNotBlank(userGroupFingerprint) && userGroupProvider instanceof ConfigurableUserGroupProvider) {
+ ((ConfigurableUserGroupProvider) userGroupProvider).inheritFingerprint(userGroupFingerprint);
+ }
+ }
+
+ @Override
+ public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
+ final String userGroupFingerprint = parseFingerprint(proposedFingerprint);
+
+ if (StringUtils.isNotBlank(userGroupFingerprint)) {
+ if (userGroupProvider instanceof ConfigurableUserGroupProvider) {
+ ((ConfigurableUserGroupProvider) userGroupProvider).checkInheritability(userGroupFingerprint);
+ } else {
+ throw new UninheritableAuthorizationsException("User/Group fingerprint is not blank and the configured UserGroupProvider does not support fingerprinting.");
+ }
+ }
+ }
+
+ private final String parseFingerprint(final String fingerprint) throws AuthorizationAccessException {
+ final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
+
+ try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
+ final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
+ final Document document = docBuilder.parse(in);
+ final Element rootElement = document.getDocumentElement();
+
+ final NodeList userGroupProviderList = rootElement.getElementsByTagName(USER_GROUP_PROVIDER_ELEMENT);
+ if (userGroupProviderList.getLength() != 1) {
+ throw new AuthorizationAccessException(String.format("Only one %s element is allowed: %s", USER_GROUP_PROVIDER_ELEMENT, fingerprint));
+ }
+
+ final Node userGroupProvider = userGroupProviderList.item(0);
+ return userGroupProvider.getTextContent();
+ } catch (SAXException | ParserConfigurationException | IOException e) {
+ throw new AuthorizationAccessException("Unable to parse fingerprint", e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
index 8b664de..c74a7d1 100644
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerBasePluginWithPolicies.java
@@ -18,38 +18,55 @@
*/
package org.apache.nifi.ranger.authorization;
+import org.apache.nifi.authorization.AccessPolicy;
+import org.apache.nifi.authorization.Group;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.User;
+import org.apache.nifi.authorization.UserGroupProvider;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.util.StringUtils;
import org.apache.ranger.plugin.service.RangerBasePlugin;
import org.apache.ranger.plugin.util.ServicePolicies;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
import java.util.stream.Collectors;
/**
- * Extends the base plugin to add ability to check if a policy exists for a given resource.
+ * Extends the base plugin to convert service policies into NiFi policy domain model.
*/
public class RangerBasePluginWithPolicies extends RangerBasePlugin {
- private AtomicReference<Set<String>> resources = new AtomicReference<>(new HashSet<>());
+ private static final Logger logger = LoggerFactory.getLogger(RangerBasePluginWithPolicies.class);
- public RangerBasePluginWithPolicies(String serviceType, String appId) {
+ private UserGroupProvider userGroupProvider;
+ private AtomicReference<PolicyLookup> policies = new AtomicReference<>(new PolicyLookup());
+
+ public RangerBasePluginWithPolicies(final String serviceType, final String appId) {
+ this(serviceType, appId, null);
+ }
+
+ public RangerBasePluginWithPolicies(final String serviceType, final String appId, final UserGroupProvider userGroupProvider) {
super(serviceType, appId);
+ this.userGroupProvider = userGroupProvider; // will be null if used outside of the ManagedRangerAuthorizer
}
@Override
- public void setPolicies(ServicePolicies policies) {
+ public void setPolicies(final ServicePolicies policies) {
super.setPolicies(policies);
if (policies == null || policies.getPolicies() == null) {
- this.resources.set(new HashSet<>());
+ this.policies.set(new PolicyLookup());
} else {
- final Set<String> newResources = policies.getPolicies().stream()
- .flatMap(p -> p.getResources().values().stream())
- .flatMap(r -> r.getValues().stream())
- .collect(Collectors.toSet());
-
- this.resources.set(newResources);
+ this.policies.set(createPolicyLookup(policies));
}
}
@@ -60,16 +77,197 @@ public class RangerBasePluginWithPolicies extends RangerBasePlugin {
*
* @return true if a policy exists for the given resource, false otherwise
*/
- public boolean doesPolicyExist(String resourceIdentifier) {
+ public boolean doesPolicyExist(final String resourceIdentifier, final RequestAction requestAction) {
if (resourceIdentifier == null) {
return false;
}
- final Set<String> currResources = resources.get();
- if (currResources == null) {
- return false;
+ final PolicyLookup policyLookup = policies.get();
+ return policyLookup.getAccessPolicy(resourceIdentifier, requestAction) != null;
+ }
+
+ public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+ return policies.get().getAccessPolicies();
+ }
+
+ public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+ return policies.get().getAccessPolicy(identifier);
+ }
+
+ public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+ return policies.get().getAccessPolicy(resourceIdentifier, action);
+ }
+
+ private PolicyLookup createPolicyLookup(final ServicePolicies servicePolicies) {
+ final Map<String, AccessPolicy> policiesByIdentifier = new HashMap<>();
+ final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource = new HashMap<>();
+
+ logger.info("Converting Ranger ServicePolicies model into NiFi policy model for viewing purposes in NiFi UI.");
+
+ servicePolicies.getPolicies().stream().forEach(policy -> {
+ // only consider policies that are enabled
+ if (Boolean.TRUE.equals(policy.getIsEnabled())) {
+ // get all the resources for this policy - excludes/recursive support disabled
+ final Set<String> resources = policy.getResources().values().stream()
+ .filter(resource -> {
+ final boolean isExclude = Boolean.TRUE.equals(resource.getIsExcludes());
+ final boolean isRecursive = Boolean.TRUE.equals(resource.getIsRecursive());
+
+ if (isExclude) {
+ logger.warn(String.format("Resources [%s] marked as an exclude policy. Skipping policy for viewing purposes. "
+ + "Will still be used for access decisions.", StringUtils.join(resource.getValues(), ", ")));
+ }
+ if (isRecursive) {
+ logger.warn(String.format("Resources [%s] marked as a recursive policy. Skipping policy for viewing purposes. "
+ + "Will still be used for access decisions.", StringUtils.join(resource.getValues(), ", ")));
+ }
+
+ return !isExclude && !isRecursive;
+ })
+ .flatMap(resource -> resource.getValues().stream())
+ .collect(Collectors.toSet());
+
+ policy.getPolicyItems().forEach(policyItem -> {
+ // get all the users for this policy item, excluding unknown users
+ final Set<String> userIds = policyItem.getUsers().stream()
+ .map(userIdentity -> getUser(userIdentity))
+ .filter(Objects::nonNull)
+ .map(user -> user.getIdentifier())
+ .collect(Collectors.toSet());
+
+ // get all groups for this policy item, excluding unknown groups
+ final Set<String> groupIds = policyItem.getGroups().stream()
+ .map(groupName -> getGroup(groupName))
+ .filter(Objects::nonNull)
+ .map(group -> group.getIdentifier())
+ .collect(Collectors.toSet());
+
+ // check if this policy item is a delegate admin
+ final boolean isDelegateAdmin = Boolean.TRUE.equals(policyItem.getDelegateAdmin());
+
+ policyItem.getAccesses().forEach(access -> {
+ try {
+ // interpret the request action
+ final RequestAction action = RequestAction.valueOf(access.getType());
+
+ // function for creating an access policy
+ final Function<String, AccessPolicy> createPolicy = resource -> new AccessPolicy.Builder()
+ .identifierGenerateFromSeed(resource + access.getType())
+ .resource(resource)
+ .action(action)
+ .addUsers(userIds)
+ .addGroups(groupIds)
+ .build();
+
+ resources.forEach(resource -> {
+ // create the access policy for the specified resource
+ final AccessPolicy accessPolicy = createPolicy.apply(resource);
+ policiesByIdentifier.put(accessPolicy.getIdentifier(), accessPolicy);
+ policiesByResource.computeIfAbsent(resource, r -> new HashMap<>()).put(action, accessPolicy);
+
+ // if this is a delegate admin, also create the admin policy for the specified resource
+ if (isDelegateAdmin) {
+ // build the admin resource identifier
+ final String adminResource;
+ if (resource.startsWith("/")) {
+ adminResource = "/policies" + resource;
+ } else {
+ adminResource = "/policies/" + resource;
+ }
+
+ final AccessPolicy adminAccessPolicy = createPolicy.apply(adminResource);
+ policiesByIdentifier.put(adminAccessPolicy.getIdentifier(), adminAccessPolicy);
+ policiesByResource.computeIfAbsent(adminResource, ar -> new HashMap<>()).put(action, adminAccessPolicy);
+ }
+ });
+ } catch (final IllegalArgumentException e) {
+ logger.warn(String.format("Unrecognized request action '%s'. Skipping policy for viewing purposes. Will still be used for access decisions.", access.getType()));
+ }
+ });
+ });
+ }
+ });
+
+ return new PolicyLookup(policiesByIdentifier, policiesByResource);
+ }
+
+ private User getUser(final String identity) {
+ if (userGroupProvider == null) {
+ // generate the user deterministically when running outside of the ManagedRangerAuthorizer
+ return new User.Builder().identifierGenerateFromSeed(identity).identity(identity).build();
+ } else {
+ // find the user in question
+ final User user = userGroupProvider.getUserByIdentity(identity);
+
+ if (user == null) {
+ logger.warn(String.format("Cannot find user '%s' in the configured User Group Provider. Skipping user for viewing purposes. Will still be used for access decisions.", identity));
+ }
+
+ return user;
+ }
+ }
+
+ private Group getGroup(final String name) {
+ if (userGroupProvider == null) {
+ // generate the group deterministically when running outside of the ManagedRangerAuthorizer
+ return new Group.Builder().identifierGenerateFromSeed(name).name(name).build();
} else {
- return currResources.contains(resourceIdentifier);
+ // find the group in question
+ final Group group = userGroupProvider.getGroups().stream().filter(g -> g.getName().equals(name)).findFirst().orElse(null);
+
+ if (group == null) {
+ logger.warn(String.format("Cannot find group '%s' in the configured User Group Provider. Skipping group for viewing purposes. Will still be used for access decisions.", name));
+ }
+
+ return group;
+ }
+ }
+
+ private static class PolicyLookup {
+
+ private final Map<String, AccessPolicy> policiesByIdentifier;
+ private final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource;
+ private final Set<AccessPolicy> allPolicies;
+
+ private PolicyLookup() {
+ this(null, null);
+ }
+
+ private PolicyLookup(final Map<String, AccessPolicy> policiesByIdentifier, final Map<String, Map<RequestAction, AccessPolicy>> policiesByResource) {
+ if (policiesByIdentifier == null) {
+ allPolicies = Collections.EMPTY_SET;
+ } else {
+ allPolicies = Collections.unmodifiableSet(new HashSet<>(policiesByIdentifier.values()));
+ }
+
+ this.policiesByIdentifier = policiesByIdentifier;
+ this.policiesByResource = policiesByResource;
+ }
+
+ private Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
+ return allPolicies;
+ }
+
+ private AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
+ if (policiesByIdentifier == null) {
+ return null;
+ }
+
+ return policiesByIdentifier.get(identifier);
+ }
+
+ private AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
+ if (policiesByResource == null) {
+ return null;
+ }
+
+ final Map<RequestAction, AccessPolicy> policiesForResource = policiesByResource.get(resourceIdentifier);
+
+ if (policiesForResource != null) {
+ return policiesForResource.get(action);
+ }
+
+ return null;
}
}
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
index 41b8106..8b98d53 100644
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/RangerNiFiAuthorizer.java
@@ -21,6 +21,7 @@ package org.apache.nifi.ranger.authorization;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.nifi.authorization.AuthorizationAuditor;
import org.apache.nifi.authorization.AuthorizationRequest;
import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.Authorizer;
@@ -33,23 +34,26 @@ import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.util.NiFiProperties;
+import org.apache.ranger.audit.model.AuthzAuditEvent;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler;
import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;
import org.apache.ranger.plugin.policyengine.RangerAccessResult;
-import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.net.MalformedURLException;
import java.util.Date;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/**
* Authorizer implementation that uses Apache Ranger to make authorization decisions.
*/
-public class RangerNiFiAuthorizer implements Authorizer {
+public class RangerNiFiAuthorizer implements Authorizer, AuthorizationAuditor {
private static final Logger logger = LoggerFactory.getLogger(RangerNiFiAuthorizer.class);
@@ -67,6 +71,8 @@ public class RangerNiFiAuthorizer implements Authorizer {
static final String HADOOP_SECURITY_AUTHENTICATION = "hadoop.security.authentication";
static final String KERBEROS_AUTHENTICATION = "kerberos";
+ private final ConcurrentMap<AuthorizationRequest, RangerAccessResult> resultLookup = new ConcurrentHashMap<>();
+
private volatile RangerBasePluginWithPolicies nifiPlugin = null;
private volatile RangerDefaultAuditHandler defaultAuditHandler = null;
private volatile String rangerAdminIdentity = null;
@@ -135,6 +141,7 @@ public class RangerNiFiAuthorizer implements Authorizer {
@Override
public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
final String identity = request.getIdentity();
+ final Set<String> userGroups = request.getGroups();
final String resourceIdentifier = request.getResource().getIdentifier();
// if a ranger admin identity was provided, and it equals the identity making the request,
@@ -159,24 +166,25 @@ public class RangerNiFiAuthorizer implements Authorizer {
rangerRequest.setAction(request.getAction().name());
rangerRequest.setAccessType(request.getAction().name());
rangerRequest.setUser(identity);
+ rangerRequest.setUserGroups(userGroups);
rangerRequest.setAccessTime(new Date());
if (!StringUtils.isBlank(clientIp)) {
rangerRequest.setClientIPAddress(clientIp);
}
- // for a direct access request use the default audit handler so we generate audit logs
- // for non-direct access provide a null result processor so no audit logs get generated
- final RangerAccessResultProcessor resultProcessor = request.isAccessAttempt() ? defaultAuditHandler : null;
-
- final RangerAccessResult result = nifiPlugin.isAccessAllowed(rangerRequest, resultProcessor);
+ final RangerAccessResult result = nifiPlugin.isAccessAllowed(rangerRequest);
if (result != null && result.getIsAllowed()) {
+ // store the result for auditing purposes later
+ resultLookup.put(request, result);
+
+ // return approved
return AuthorizationResult.approved();
} else {
// if result.getIsAllowed() is false, then we need to determine if it was because no policy exists for the
// given resource, or if it was because a policy exists but not for the given user or action
- final boolean doesPolicyExist = nifiPlugin.doesPolicyExist(request.getResource().getIdentifier());
+ final boolean doesPolicyExist = nifiPlugin.doesPolicyExist(request.getResource().getIdentifier(), request.getAction());
if (doesPolicyExist) {
final String reason = result == null ? null : result.getReason();
@@ -184,6 +192,9 @@ public class RangerNiFiAuthorizer implements Authorizer {
logger.debug(String.format("Unable to authorize %s due to %s", identity, reason));
}
+ // store the result for auditing purposes later
+ resultLookup.put(request, result);
+
// a policy does exist for the resource so we were really denied access here
return AuthorizationResult.denied(request.getExplanationSupplier().get());
} else {
@@ -194,6 +205,21 @@ public class RangerNiFiAuthorizer implements Authorizer {
}
@Override
+ public void auditAccessAttempt(final AuthorizationRequest request, final AuthorizationResult result) {
+ final RangerAccessResult rangerResult = resultLookup.remove(request);
+
+ if (rangerResult != null && rangerResult.getIsAudited()) {
+ AuthzAuditEvent event = defaultAuditHandler.getAuthzEvents(rangerResult);
+
+ // update the event with the originally requested resource
+ event.setResourceType(RANGER_NIFI_RESOURCE_NAME);
+ event.setResourcePath(request.getRequestedResource().getIdentifier());
+
+ defaultAuditHandler.logAuthzAudit(event);
+ }
+ }
+
+ @Override
public void preDestruction() throws AuthorizerDestructionException {
if (nifiPlugin != null) {
try {
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
index 607d979..34d8797 100755
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/resources/META-INF/services/org.apache.nifi.authorization.Authorizer
@@ -13,3 +13,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
org.apache.nifi.ranger.authorization.RangerNiFiAuthorizer
+org.apache.nifi.ranger.authorization.ManagedRangerAuthorizer
http://git-wip-us.apache.org/repos/asf/nifi/blob/743c6b9c/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java
new file mode 100644
index 0000000..bd1f6e1
--- /dev/null
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/test/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizerTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.ranger.authorization;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.nifi.authorization.AuthorizerConfigurationContext;
+import org.apache.nifi.authorization.AuthorizerInitializationContext;
+import org.apache.nifi.authorization.ConfigurableUserGroupProvider;
+import org.apache.nifi.authorization.UserGroupProvider;
+import org.apache.nifi.authorization.UserGroupProviderLookup;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
+import org.apache.nifi.util.MockPropertyValue;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ManagedRangerAuthorizerTest {
+
+ private static final String TENANT_FINGERPRINT =
+ "<tenants>"
+ + "<user identifier=\"user-id-1\" identity=\"user-1\"></user>"
+ + "<group identifier=\"group-id-1\" name=\"group-1\">"
+ + "<groupUser identifier=\"user-id-1\"></groupUser>"
+ + "</group>"
+ + "</tenants>";
+
+ private static final String EMPTY_FINGERPRINT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
+ + "<managedRangerAuthorizations>"
+ + "<userGroupProvider/>"
+ + "</managedRangerAuthorizations>";
+
+ private static final String NON_EMPTY_FINGERPRINT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
+ + "<managedRangerAuthorizations>"
+ + "<userGroupProvider>"
+ + "<tenants>"
+ + "<user identifier=\"user-id-1\" identity=\"user-1\"></user>"
+ + "<group identifier=\"group-id-1\" name=\"group-1\">"
+ + "<groupUser identifier=\"user-id-1\"></groupUser>"
+ + "</group>"
+ + "</tenants>"
+ + "</userGroupProvider>"
+ + "</managedRangerAuthorizations>";
+
+ private final String serviceType = "nifiService";
+ private final String appId = "nifiAppId";
+
+ @Before
+ public void setup() {
+ // have to initialize this system property before anything else
+ File krb5conf = new File("src/test/resources/krb5.conf");
+ assertTrue(krb5conf.exists());
+ System.setProperty("java.security.krb5.conf", krb5conf.getAbsolutePath());
+
+ // rest the authentication to simple in case any tests set it to kerberos
+ final Configuration securityConf = new Configuration();
+ securityConf.set(RangerNiFiAuthorizer.HADOOP_SECURITY_AUTHENTICATION, "simple");
+ UserGroupInformation.setConfiguration(securityConf);
+
+ assertFalse(UserGroupInformation.isSecurityEnabled());
+ }
+
+ @Test
+ public void testNonConfigurableFingerPrint() throws Exception {
+ final UserGroupProvider userGroupProvider = mock(UserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ Assert.assertEquals(EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
+ }
+
+ @Test
+ public void testConfigurableEmptyFingerPrint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+ when(userGroupProvider.getFingerprint()).thenReturn("");
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ Assert.assertEquals(EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
+ }
+
+ @Test
+ public void testConfigurableFingerPrint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+ when(userGroupProvider.getFingerprint()).thenReturn(TENANT_FINGERPRINT);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ Assert.assertEquals(NON_EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
+ }
+
+ @Test
+ public void testInheritEmptyFingerprint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.inheritFingerprint(EMPTY_FINGERPRINT);
+
+ verify(userGroupProvider, times(0)).inheritFingerprint(anyString());
+ }
+
+ @Test(expected = AuthorizationAccessException.class)
+ public void testInheritInvalidFingerprint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.inheritFingerprint("not a valid fingerprint");
+ }
+
+ @Test
+ public void testInheritNonEmptyFingerprint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.inheritFingerprint(NON_EMPTY_FINGERPRINT);
+
+ verify(userGroupProvider, times(1)).inheritFingerprint(TENANT_FINGERPRINT);
+ }
+
+ @Test
+ public void testCheckInheritEmptyFingerprint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.checkInheritability(EMPTY_FINGERPRINT);
+
+ verify(userGroupProvider, times(0)).inheritFingerprint(anyString());
+ }
+
+ @Test(expected = AuthorizationAccessException.class)
+ public void testCheckInheritInvalidFingerprint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.checkInheritability("not a valid fingerprint");
+ }
+
+ @Test
+ public void testCheckInheritNonEmptyFingerprint() throws Exception {
+ final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.checkInheritability(NON_EMPTY_FINGERPRINT);
+
+ verify(userGroupProvider, times(1)).checkInheritability(TENANT_FINGERPRINT);
+ }
+
+ @Test(expected = UninheritableAuthorizationsException.class)
+ public void testCheckInheritNonConfigurableUserGroupProvider() throws Exception {
+ final UserGroupProvider userGroupProvider = mock(UserGroupProvider.class);
+
+ final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
+ managedRangerAuthorizer.checkInheritability(NON_EMPTY_FINGERPRINT);
+ }
+
+ private ManagedRangerAuthorizer getStandardManagedAuthorizer(final UserGroupProvider userGroupProvider) {
+ final ManagedRangerAuthorizer managedAuthorizer = new ManagedRangerAuthorizer();
+
+ final AuthorizerConfigurationContext configurationContext = mock(AuthorizerConfigurationContext.class);
+ when(configurationContext.getProperty(eq("User Group Provider"))).thenReturn(new MockPropertyValue("user-group-provider", null));
+ when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_SECURITY_PATH_PROP))).thenReturn(new MockPropertyValue("src/test/resources/ranger/ranger-nifi-security.xml"));
+ when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_AUDIT_PATH_PROP))).thenReturn(new MockPropertyValue("src/test/resources/ranger/ranger-nifi-audit.xml"));
+ when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_APP_ID_PROP))).thenReturn(new MockPropertyValue(appId));
+ when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_SERVICE_TYPE_PROP))).thenReturn(new MockPropertyValue(serviceType));
+
+ final UserGroupProviderLookup userGroupProviderLookup = mock(UserGroupProviderLookup.class);
+ when(userGroupProviderLookup.getUserGroupProvider("user-group-provider")).thenReturn(userGroupProvider);
+
+ final AuthorizerInitializationContext initializationContext = mock(AuthorizerInitializationContext.class);
+ when(initializationContext.getUserGroupProviderLookup()).thenReturn(userGroupProviderLookup);
+
+ managedAuthorizer.initialize(initializationContext);
+ managedAuthorizer.onConfigured(configurationContext);
+
+ return managedAuthorizer;
+ }
+}
\ No newline at end of file