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 as denied when the parent authorizable is null (no more inheritance). - Updating unit tests as appropriate. - Addressing issues with broken web-api integration tests.

NIFI-4032: - Generating the appropriate fingerprint for the ManagedRangerAuthorizer based on whether the UserGroupProvider is configurable. - Adding unit tests.

Signed-off-by: Yolanda M. Davis <ymdavis@apache.org>

This closes #2019
This commit is contained in:
Matt Gilman 2017-06-28 10:17:17 -04:00 committed by Yolanda M. Davis
parent 10692256d6
commit 743c6b9c17
34 changed files with 1637 additions and 849 deletions

View File

@ -0,0 +1,30 @@
/*
* 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;
public interface AuthorizationAuditor {
/**
* Audits an authorization request. Will be invoked for any Approved or Denied results. ResourceNotFound
* will either re-attempt authorization using a parent resource or will generate a failure result and
* audit that.
*
* @param request the request for authorization
* @param result the authorization result
*/
void auditAccessAttempt(final AuthorizationRequest request, final AuthorizationResult result);
}

View File

@ -31,6 +31,7 @@ public class AuthorizationRequest {
public static final String DEFAULT_EXPLANATION = "Unable to perform the desired action.";
private final Resource resource;
private final Resource requestedResource;
private final String identity;
private final Set<String> groups;
private final RequestAction action;
@ -64,6 +65,12 @@ public class AuthorizationRequest {
return explanation;
}
};
if (builder.requestedResource == null) {
this.requestedResource = builder.resource;
} else {
this.requestedResource = builder.requestedResource;
}
}
/**
@ -75,6 +82,17 @@ public class AuthorizationRequest {
return resource;
}
/**
* The original Resource being requested. In cases with inherited policies, this will be a ancestor resource of
* of the current resource. The initial request, and cases without inheritance, the requested resource will be
* the same as the current resource.
*
* @return The requested resource
*/
public Resource getRequestedResource() {
return requestedResource;
}
/**
* The identity accessing the Resource. May be null if the user could not authenticate.
*
@ -154,6 +172,7 @@ public class AuthorizationRequest {
public static final class Builder {
private Resource resource;
private Resource requestedResource;
private String identity;
private Set<String> groups;
private Boolean isAnonymous;
@ -168,6 +187,11 @@ public class AuthorizationRequest {
return this;
}
public Builder requestedResource(final Resource requestedResource) {
this.requestedResource = requestedResource;
return this;
}
public Builder identity(final String identity) {
this.identity = identity;
return this;

View File

@ -17,6 +17,7 @@
package org.apache.nifi.authorization.resource;
import org.apache.nifi.authorization.AccessDeniedException;
import org.apache.nifi.authorization.AuthorizationAuditor;
import org.apache.nifi.authorization.AuthorizationRequest;
import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
@ -45,6 +46,17 @@ public interface Authorizable {
*/
Resource getResource();
/**
* The originally requested resource for this Authorizable. Because policies are inherited, if a resource
* does not have a policy, this Authorizable may represent a parent resource and this method will return
* the originally requested resource.
*
* @return the originally requested resource
*/
default Resource getRequestedResource() {
return getResource();
}
/**
* Returns whether the current user is authorized for the specified action on the specified resource. This
* method does not imply the user is directly attempting to access the specified resource. If the user is
@ -82,6 +94,7 @@ public interface Authorizable {
}
final Resource resource = getResource();
final Resource requestedResource = getRequestedResource();
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity(user.getIdentity())
.groups(user.getGroups())
@ -89,6 +102,7 @@ public interface Authorizable {
.accessAttempt(false)
.action(action)
.resource(resource)
.requestedResource(requestedResource)
.resourceContext(resourceContext)
.userContext(userContext)
.explanationSupplier(() -> {
@ -122,6 +136,11 @@ public interface Authorizable {
return parent.getParentAuthorizable();
}
@Override
public Resource getRequestedResource() {
return requestedResource;
}
@Override
public Resource getResource() {
final Resource parentResource = parent.getResource();
@ -187,6 +206,7 @@ public interface Authorizable {
}
final Resource resource = getResource();
final Resource requestedResource = getRequestedResource();
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity(user.getIdentity())
.groups(user.getGroups())
@ -194,6 +214,7 @@ public interface Authorizable {
.accessAttempt(true)
.action(action)
.resource(resource)
.requestedResource(requestedResource)
.resourceContext(resourceContext)
.userContext(userContext)
.explanationSupplier(() -> {
@ -215,7 +236,15 @@ public interface Authorizable {
if (Result.ResourceNotFound.equals(result.getResult())) {
final Authorizable parent = getParentAuthorizable();
if (parent == null) {
throw new AccessDeniedException("No applicable policies could be found.");
final AuthorizationResult failure = AuthorizationResult.denied("No applicable policies could be found.");
// audit authorization request
if (authorizer instanceof AuthorizationAuditor) {
((AuthorizationAuditor) authorizer).auditAccessAttempt(request, failure);
}
// denied
throw new AccessDeniedException(failure.getExplanation());
} else {
// create a custom authorizable to override the safe description but still defer to the parent authorizable
final Authorizable parentProxy = new Authorizable() {
@ -224,6 +253,11 @@ public interface Authorizable {
return parent.getParentAuthorizable();
}
@Override
public Resource getRequestedResource() {
return requestedResource;
}
@Override
public Resource getResource() {
final Resource parentResource = parent.getResource();

View File

@ -16,170 +16,21 @@
*/
package org.apache.nifi.authorization;
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.apache.nifi.nar.NarCloseable;
import org.apache.commons.lang3.ClassUtils;
import java.util.Set;
import java.lang.reflect.Proxy;
import java.util.List;
public final class AccessPolicyProviderFactory {
public static AccessPolicyProvider withNarLoader(final AccessPolicyProvider baseAccessPolicyProvider) {
if (baseAccessPolicyProvider instanceof ConfigurableAccessPolicyProvider) {
final ConfigurableAccessPolicyProvider baseConfigurableAccessPolicyProvider = (ConfigurableAccessPolicyProvider) baseAccessPolicyProvider;
return new ConfigurableAccessPolicyProvider() {
@Override
public AccessPolicy addAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.addAccessPolicy(accessPolicy);
}
}
public static AccessPolicyProvider withNarLoader(final AccessPolicyProvider baseAccessPolicyProvider, final ClassLoader classLoader) {
final AccessPolicyProviderInvocationHandler invocationHandler = new AccessPolicyProviderInvocationHandler(baseAccessPolicyProvider, classLoader);
@Override
public boolean isConfigurable(AccessPolicy accessPolicy) {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.isConfigurable(accessPolicy);
}
}
// extract all interfaces... baseAccessPolicyProvider is non null so getAllInterfaces is non null
final List<Class<?>> interfaceList = ClassUtils.getAllInterfaces(baseAccessPolicyProvider.getClass());
final Class<?>[] interfaces = interfaceList.toArray(new Class<?>[interfaceList.size()]);
@Override
public AccessPolicy updateAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.updateAccessPolicy(accessPolicy);
}
}
@Override
public AccessPolicy deleteAccessPolicy(AccessPolicy accessPolicy) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.deleteAccessPolicy(accessPolicy);
}
}
@Override
public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.getAccessPolicies();
}
}
@Override
public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.getAccessPolicy(identifier);
}
}
@Override
public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.getAccessPolicy(resourceIdentifier, action);
}
}
@Override
public UserGroupProvider getUserGroupProvider() {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.getUserGroupProvider();
}
}
@Override
public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableAccessPolicyProvider.inheritFingerprint(fingerprint);
}
}
@Override
public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableAccessPolicyProvider.checkInheritability(proposedFingerprint);
}
}
@Override
public String getFingerprint() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableAccessPolicyProvider.getFingerprint();
}
}
@Override
public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableAccessPolicyProvider.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableAccessPolicyProvider.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableAccessPolicyProvider.preDestruction();
}
}
};
} else {
return new AccessPolicyProvider() {
@Override
public Set<AccessPolicy> getAccessPolicies() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseAccessPolicyProvider.getAccessPolicies();
}
}
@Override
public AccessPolicy getAccessPolicy(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseAccessPolicyProvider.getAccessPolicy(identifier);
}
}
@Override
public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseAccessPolicyProvider.getAccessPolicy(resourceIdentifier, action);
}
}
@Override
public UserGroupProvider getUserGroupProvider() {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseAccessPolicyProvider.getUserGroupProvider();
}
}
@Override
public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAccessPolicyProvider.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAccessPolicyProvider.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseAccessPolicyProvider.preDestruction();
}
}
};
}
return (AccessPolicyProvider) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
private AccessPolicyProviderFactory() {}

View File

@ -0,0 +1,54 @@
/*
* 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;
import org.apache.nifi.nar.NarCloseable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AccessPolicyProviderInvocationHandler implements InvocationHandler {
private final AccessPolicyProvider accessPolicyProvider;
private final ClassLoader classLoader;
public AccessPolicyProviderInvocationHandler(final AccessPolicyProvider accessPolicyProvider, final ClassLoader classLoader) {
this.accessPolicyProvider = accessPolicyProvider;
this.classLoader = classLoader;
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
if (AccessPolicyProvider.class.getMethod("getUserGroupProvider").equals(method)) {
final UserGroupProvider userGroupProvider = (UserGroupProvider) method.invoke(accessPolicyProvider, args);
if (userGroupProvider == null) {
return userGroupProvider;
} else {
return UserGroupProviderFactory.withNarLoader(userGroupProvider, classLoader);
}
} else {
return method.invoke(accessPolicyProvider, args);
}
} catch (final InvocationTargetException e) {
// If the proxied instance throws an Exception, it'll be wrapped in an InvocationTargetException. We want
// to instead re-throw what the proxied instance threw, so we pull it out of the InvocationTargetException.
throw e.getCause();
}
}
}

View File

@ -16,12 +16,15 @@
*/
package org.apache.nifi.authorization;
import org.apache.commons.lang3.ClassUtils;
import org.apache.nifi.authorization.AuthorizationResult.Result;
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.apache.nifi.nar.NarCloseable;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Set;
public final class AuthorizerFactory {
@ -68,6 +71,16 @@ public final class AuthorizerFactory {
return false;
}
private static void audit(final Authorizer authorizer, final AuthorizationRequest request, final AuthorizationResult result) {
// audit when...
// 1 - the authorizer supports auditing
// 2 - the request is an access attempt
// 3 - the result is either approved/denied, when resource is not found a subsequent request may be following with the parent resource
if (authorizer instanceof AuthorizationAuditor && request.isAccessAttempt() && !Result.ResourceNotFound.equals(result.getResult())) {
((AuthorizationAuditor) authorizer).auditAccessAttempt(request, result);
}
}
public static Authorizer installIntegrityChecks(final Authorizer baseAuthorizer) {
if (baseAuthorizer instanceof ManagedAuthorizer) {
final ManagedAuthorizer baseManagedAuthorizer = (ManagedAuthorizer) baseAuthorizer;
@ -309,7 +322,12 @@ public final class AuthorizerFactory {
@Override
public AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException {
return baseManagedAuthorizer.authorize(request);
final AuthorizationResult result = baseAuthorizer.authorize(request);
// audit the authorization request
audit(baseAuthorizer, request, result);
return result;
}
@Override
@ -352,7 +370,32 @@ public final class AuthorizerFactory {
}
};
} else {
return baseAuthorizer;
return new Authorizer() {
@Override
public AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException {
final AuthorizationResult result = baseAuthorizer.authorize(request);
// audit the authorization request
audit(baseAuthorizer, request, result);
return result;
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
baseAuthorizer.initialize(initializationContext);
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
baseAuthorizer.onConfigured(configurationContext);
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
baseAuthorizer.preDestruction();
}
};
}
}
@ -363,96 +406,13 @@ public final class AuthorizerFactory {
* @return authorizer
*/
public static Authorizer withNarLoader(final Authorizer baseAuthorizer, final ClassLoader classLoader) {
if (baseAuthorizer instanceof ManagedAuthorizer) {
final ManagedAuthorizer baseManagedAuthorizer = (ManagedAuthorizer) baseAuthorizer;
return new ManagedAuthorizer() {
@Override
public String getFingerprint() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
return baseManagedAuthorizer.getFingerprint();
}
}
final AuthorizerInvocationHandler invocationHandler = new AuthorizerInvocationHandler(baseAuthorizer, classLoader);
@Override
public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseManagedAuthorizer.inheritFingerprint(fingerprint);
}
}
// extract all interfaces... baseAuthorizer is non null so getAllInterfaces is non null
final List<Class<?>> interfaceList = ClassUtils.getAllInterfaces(baseAuthorizer.getClass());
final Class<?>[] interfaces = interfaceList.toArray(new Class<?>[interfaceList.size()]);
@Override
public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseManagedAuthorizer.checkInheritability(proposedFingerprint);
}
}
@Override
public AccessPolicyProvider getAccessPolicyProvider() {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
return baseManagedAuthorizer.getAccessPolicyProvider();
}
}
@Override
public AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
return baseManagedAuthorizer.authorize(request);
}
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseManagedAuthorizer.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseManagedAuthorizer.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseManagedAuthorizer.preDestruction();
}
}
};
} else {
return new Authorizer() {
@Override
public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
return baseAuthorizer.authorize(request);
}
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseAuthorizer.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseAuthorizer.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
baseAuthorizer.preDestruction();
}
}
};
}
return (Authorizer) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
private AuthorizerFactory() {}

View File

@ -225,7 +225,7 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, UserG
}
}
return UserGroupProviderFactory.withNarLoader(instance);
return UserGroupProviderFactory.withNarLoader(instance, userGroupProviderClassLoader);
}
private AccessPolicyProvider createAccessPolicyProvider(final String identifier, final String accessPolicyProviderClassName) throws Exception {
@ -273,7 +273,7 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, UserG
}
}
return AccessPolicyProviderFactory.withNarLoader(instance);
return AccessPolicyProviderFactory.withNarLoader(instance, accessPolicyProviderClassLoader);
}
private Authorizer createAuthorizer(final String identifier, final String authorizerClassName, final String classpathResources) throws Exception {
@ -321,12 +321,12 @@ public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, UserG
}
}
if(StringUtils.isNotEmpty(classpathResources)) {
if (StringUtils.isNotEmpty(classpathResources)) {
URL[] urls = ClassLoaderUtils.getURLsForClasspath(classpathResources, null, true);
authorizerClassLoader = new URLClassLoader(urls, authorizerClassLoader);
}
return AuthorizerFactory.installIntegrityChecks(AuthorizerFactory.withNarLoader(instance,authorizerClassLoader));
return AuthorizerFactory.installIntegrityChecks(AuthorizerFactory.withNarLoader(instance, authorizerClassLoader));
}
private AuthorizerConfigurationContext loadAuthorizerConfiguration(final String identifier, final List<Property> properties) {

View File

@ -0,0 +1,54 @@
/*
* 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;
import org.apache.nifi.nar.NarCloseable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AuthorizerInvocationHandler implements InvocationHandler {
private final Authorizer authorizer;
private final ClassLoader classLoader;
public AuthorizerInvocationHandler(final Authorizer authorizer, final ClassLoader classLoader) {
this.authorizer = authorizer;
this.classLoader = classLoader;
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
if (ManagedAuthorizer.class.getMethod("getAccessPolicyProvider").equals(method)) {
final AccessPolicyProvider accessPolicyProvider = (AccessPolicyProvider) method.invoke(authorizer, args);
if (accessPolicyProvider == null) {
return accessPolicyProvider;
} else {
return AccessPolicyProviderFactory.withNarLoader(accessPolicyProvider, classLoader);
}
} else {
return method.invoke(authorizer, args);
}
} catch (final InvocationTargetException e) {
// If the proxied instance throws an Exception, it'll be wrapped in an InvocationTargetException. We want
// to instead re-throw what the proxied instance threw, so we pull it out of the InvocationTargetException.
throw e.getCause();
}
}
}

View File

@ -16,226 +16,21 @@
*/
package org.apache.nifi.authorization;
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.apache.nifi.nar.NarCloseable;
import org.apache.commons.lang3.ClassUtils;
import java.util.Set;
import java.lang.reflect.Proxy;
import java.util.List;
public final class UserGroupProviderFactory {
public static UserGroupProvider withNarLoader(final UserGroupProvider baseUserGroupProvider) {
if (baseUserGroupProvider instanceof ConfigurableUserGroupProvider) {
final ConfigurableUserGroupProvider baseConfigurableUserGroupProvider = (ConfigurableUserGroupProvider) baseUserGroupProvider;
return new ConfigurableUserGroupProvider() {
@Override
public User addUser(User user) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.addUser(user);
}
}
public static UserGroupProvider withNarLoader(final UserGroupProvider baseUserGroupProvider, final ClassLoader classLoader) {
final UserGroupProviderInvocationHandler invocationHandler = new UserGroupProviderInvocationHandler(baseUserGroupProvider, classLoader);
@Override
public boolean isConfigurable(User user) {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.isConfigurable(user);
}
}
// extract all interfaces... baseUserGroupProvider is non null so getAllInterfaces is non null
final List<Class<?>> interfaceList = ClassUtils.getAllInterfaces(baseUserGroupProvider.getClass());
final Class<?>[] interfaces = interfaceList.toArray(new Class<?>[interfaceList.size()]);
@Override
public User updateUser(User user) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.updateUser(user);
}
}
@Override
public User deleteUser(User user) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.deleteUser(user);
}
}
@Override
public Group addGroup(Group group) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.addGroup(group);
}
}
@Override
public boolean isConfigurable(Group group) {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.isConfigurable(group);
}
}
@Override
public Group updateGroup(Group group) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.updateGroup(group);
}
}
@Override
public Group deleteGroup(Group group) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.deleteGroup(group);
}
}
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getUsers();
}
}
@Override
public User getUser(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getUser(identifier);
}
}
@Override
public User getUserByIdentity(String identity) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getUserByIdentity(identity);
}
}
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getGroups();
}
}
@Override
public Group getGroup(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getGroup(identifier);
}
}
@Override
public UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getUserAndGroups(identity);
}
}
@Override
public void inheritFingerprint(String fingerprint) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableUserGroupProvider.inheritFingerprint(fingerprint);
}
}
@Override
public void checkInheritability(String proposedFingerprint) throws AuthorizationAccessException, UninheritableAuthorizationsException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableUserGroupProvider.checkInheritability(proposedFingerprint);
}
}
@Override
public String getFingerprint() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseConfigurableUserGroupProvider.getFingerprint();
}
}
@Override
public void initialize(UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableUserGroupProvider.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableUserGroupProvider.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseConfigurableUserGroupProvider.preDestruction();
}
}
};
} else {
return new UserGroupProvider() {
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseUserGroupProvider.getUsers();
}
}
@Override
public User getUser(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseUserGroupProvider.getUser(identifier);
}
}
@Override
public User getUserByIdentity(String identity) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseUserGroupProvider.getUserByIdentity(identity);
}
}
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseUserGroupProvider.getGroups();
}
}
@Override
public Group getGroup(String identifier) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseUserGroupProvider.getGroup(identifier);
}
}
@Override
public UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
return baseUserGroupProvider.getUserAndGroups(identity);
}
}
@Override
public void initialize(UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseUserGroupProvider.initialize(initializationContext);
}
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseUserGroupProvider.onConfigured(configurationContext);
}
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
baseUserGroupProvider.preDestruction();
}
}
};
}
return (UserGroupProvider) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
private UserGroupProviderFactory() {}

View File

@ -0,0 +1,45 @@
/*
* 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;
import org.apache.nifi.nar.NarCloseable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class UserGroupProviderInvocationHandler implements InvocationHandler {
private final UserGroupProvider userGroupProvider;
private final ClassLoader classLoader;
public UserGroupProviderInvocationHandler(final UserGroupProvider userGroupProvider, final ClassLoader classLoader) {
this.userGroupProvider = userGroupProvider;
this.classLoader = classLoader;
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) {
return method.invoke(userGroupProvider, args);
} catch (final InvocationTargetException e) {
// If the proxied instance throws an Exception, it'll be wrapped in an InvocationTargetException. We want
// to instead re-throw what the proxied instance threw, so we pull it out of the InvocationTargetException.
throw e.getCause();
}
}
}

View File

@ -16,6 +16,7 @@
*/
package org.apache.nifi.authorization;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.junit.Assert;
import org.junit.Test;
@ -25,6 +26,9 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class AuthorizerFactoryTest {
@Test(expected = AuthorizerCreationException.class)
@ -261,4 +265,83 @@ public class AuthorizerFactoryTest {
}
}
@Test
public void testAuditInvoked() {
User user1 = new User.Builder().identifier("user-id-1").identity("user-1").build();
AccessPolicy policy1 = new AccessPolicy.Builder()
.identifier("policy-id-1")
.resource("resource1")
.action(RequestAction.READ)
.addUser(user1.getIdentifier())
.build();
Set<AccessPolicy> policies = new LinkedHashSet<>();
policies.add(policy1);
Set<User> users = new LinkedHashSet<>();
users.add(user1);
final MockPolicyBasedAuthorizer mockAuthorizer = new MockPolicyBasedAuthorizer(new HashSet<>(), users, policies);
AuthorizerConfigurationContext context = Mockito.mock(AuthorizerConfigurationContext.class);
Authorizer authorizer = AuthorizerFactory.installIntegrityChecks(mockAuthorizer);
authorizer.onConfigured(context);
final AuthorizationRequest accessAttempt = new AuthorizationRequest.Builder()
.resource(new MockResource("resource1", "Resource 1"))
.identity("user-1")
.action(RequestAction.READ)
.accessAttempt(true)
.anonymous(false)
.build();
final AuthorizationResult accessAttemptResult = authorizer.authorize(accessAttempt);
assertTrue(Result.Approved.equals(accessAttemptResult.getResult()));
assertTrue(mockAuthorizer.isAudited(accessAttempt));
final AuthorizationRequest nonAccessAttempt = new AuthorizationRequest.Builder()
.resource(new MockResource("resource1", "Resource 1"))
.identity("user-1")
.accessAttempt(false)
.action(RequestAction.READ)
.anonymous(false)
.build();
final AuthorizationResult nonAccessAttempResult = authorizer.authorize(nonAccessAttempt);
assertTrue(Result.Approved.equals(nonAccessAttempResult.getResult()));
assertFalse(mockAuthorizer.isAudited(nonAccessAttempt));
}
/**
* Resource implementation for testing.
*/
private static class MockResource implements Resource {
private final String identifier;
private final String name;
public MockResource(String identifier, String name) {
this.identifier = identifier;
this.name = name;
}
@Override
public String getIdentifier() {
return identifier;
}
@Override
public String getName() {
return name;
}
@Override
public String getSafeDescription() {
return name;
}
}
}

View File

@ -27,12 +27,14 @@ import java.util.stream.Collectors;
/**
* Mock implementation of AbstractPolicyBasedAuthorizer.
*/
public class MockPolicyBasedAuthorizer extends AbstractPolicyBasedAuthorizer {
public class MockPolicyBasedAuthorizer extends AbstractPolicyBasedAuthorizer implements AuthorizationAuditor {
private Set<Group> groups = new HashSet<>();
private Set<User> users = new HashSet<>();
private Set<AccessPolicy> policies = new HashSet<>();
private Set<AuthorizationRequest> audited = new HashSet();
public MockPolicyBasedAuthorizer() {
}
@ -143,7 +145,9 @@ public class MockPolicyBasedAuthorizer extends AbstractPolicyBasedAuthorizer {
return new UsersAndAccessPolicies() {
@Override
public AccessPolicy getAccessPolicy(String resourceIdentifier, RequestAction action) {
return null;
return policies.stream()
.filter(policy -> policy.getResource().equals(resourceIdentifier) && policy.getAction().equals(action))
.findFirst().orElse(null);
}
@Override
@ -165,6 +169,15 @@ public class MockPolicyBasedAuthorizer extends AbstractPolicyBasedAuthorizer {
};
}
@Override
public void auditAccessAttempt(AuthorizationRequest request, AuthorizationResult result) {
audited.add(request);
}
public boolean isAudited(AuthorizationRequest request) {
return audited.contains(request);
}
@Override
public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {

View File

@ -62,6 +62,27 @@ public interface AuthorizableLookup {
*/
Authorizable getCounters();
/**
* Get the authorizable for retrieving resources.
*
* @return authorizable
*/
Authorizable getResource();
/**
* Get the authorizable for site to site.
*
* @return authorizable
*/
Authorizable getSiteToSite();
/**
* Get the authorizable for the flow.
*
* @return authorizable
*/
Authorizable getFlow();
/**
* Get the authorizable RootGroup InputPort.
*

View File

@ -108,6 +108,42 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
}
};
private static final Authorizable RESOURCE_AUTHORIZABLE = new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getResourceResource();
}
};
private static final Authorizable SITE_TO_SITE_AUTHORIZABLE = new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getSiteToSiteResource();
}
};
private static final Authorizable FLOW_AUTHORIZABLE = new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return ResourceFactory.getFlowResource();
}
};
private static final Authorizable SYSTEM_AUTHORIZABLE = new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
@ -268,6 +304,21 @@ class StandardAuthorizableLookup implements AuthorizableLookup {
return COUNTERS_AUTHORIZABLE;
}
@Override
public Authorizable getResource() {
return RESOURCE_AUTHORIZABLE;
}
@Override
public Authorizable getSiteToSite() {
return SITE_TO_SITE_AUTHORIZABLE;
}
@Override
public Authorizable getFlow() {
return FLOW_AUTHORIZABLE;
}
private ConfiguredComponent findControllerServiceReferencingComponent(final ControllerServiceReference referencingComponents, final String id) {
ConfiguredComponent reference = null;
for (final ConfiguredComponent component : referencingComponents.getReferencingComponents()) {

View File

@ -25,17 +25,11 @@ import org.apache.nifi.action.Operation;
import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
import org.apache.nifi.action.details.FlowChangeConfigureDetails;
import org.apache.nifi.admin.service.AuditService;
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.AuthorizeControllerServiceReference;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.ComponentAuthorizable;
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;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
@ -100,29 +94,8 @@ 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())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
.userContext(userContext)
.explanationSupplier(() -> "Unable to view the user interface.")
.build();
final AuthorizationResult result = authorizer.authorize(request);
if (!Result.Approved.equals(result.getResult())) {
throw new AccessDeniedException(result.getExplanation());
}
final Authorizable flow = lookup.getFlow();
flow.authorize(authorizer, RequestAction.READ, user);
});
}

View File

@ -24,17 +24,11 @@ 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.AuthorizeControllerServiceReference;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.ComponentAuthorizable;
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.controller.FlowController;
import org.apache.nifi.web.IllegalClusterResourceRequestException;
@ -71,8 +65,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* RESTful endpoint for managing a Flow Controller.
@ -97,42 +89,10 @@ public class ControllerResource extends ApplicationResource {
* Authorizes access to the flow.
*/
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())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
.userContext(userContext)
.explanationSupplier(() -> {
final StringBuilder explanation = new StringBuilder("Unable to ");
if (RequestAction.READ.equals(action)) {
explanation.append("view ");
} else {
explanation.append("modify ");
}
explanation.append("the controller.");
return explanation.toString();
})
.build();
final AuthorizationResult result = authorizer.authorize(request);
if (!Result.Approved.equals(result.getResult())) {
throw new AccessDeniedException(result.getExplanation());
}
serviceFacade.authorizeAccess(lookup -> {
final Authorizable controller = lookup.getController();
controller.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
});
}
/**

View File

@ -23,16 +23,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.cluster.manager.exception.UnknownNodeException;
@ -57,8 +50,6 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;
/**
@ -81,42 +72,10 @@ public class CountersResource extends ApplicationResource {
* Authorizes access to the flow.
*/
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())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
.userContext(userContext)
.explanationSupplier(() -> {
final StringBuilder explanation = new StringBuilder("Unable to ");
if (RequestAction.READ.equals(action)) {
explanation.append("view ");
} else {
explanation.append("modify ");
}
explanation.append("counters.");
return explanation.toString();
})
.build();
final AuthorizationResult result = authorizer.authorize(request);
if (!Result.Approved.equals(result.getResult())) {
throw new AccessDeniedException(result.getExplanation());
}
serviceFacade.authorizeAccess(lookup -> {
final Authorizable counters = lookup.getCounters();
counters.authorize(authorizer, action, NiFiUserUtils.getNiFiUser());
});
}
/**

View File

@ -24,15 +24,9 @@ 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.Authorizable;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.bundle.Bundle;
@ -204,31 +198,10 @@ public class FlowResource extends ApplicationResource {
* Authorizes access to the flow.
*/
private void authorizeFlow() {
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())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
.userContext(userContext)
.explanationSupplier(() -> "Unable to view the user interface.")
.build();
final AuthorizationResult result = authorizer.authorize(request);
if (!Result.Approved.equals(result.getResult())) {
throw new AccessDeniedException(result.getExplanation());
}
serviceFacade.authorizeAccess(lookup -> {
final Authorizable flow = lookup.getFlow();
flow.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
});
}
// ----
@ -2225,29 +2198,8 @@ public class FlowResource extends ApplicationResource {
}
// a component for the specified id could not be found, attempt to authorize based on read to the controller
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())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(RequestAction.READ)
.userContext(userContext)
.explanationSupplier(() -> String.format("Unable to find component with id '%s' and unable to view the controller.", componentId))
.build();
final AuthorizationResult result = authorizer.authorize(request);
if (!Result.Approved.equals(result.getResult())) {
throw new AccessDeniedException(result.getExplanation());
}
final Authorizable controller = lookup.getController();
controller.authorize(authorizer, RequestAction.READ, user);
});
// Note: History requests are not replicated throughout the cluster and are instead handled by the nodes independently

View File

@ -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());
});
}
/**

View File

@ -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());
});
}
/**

View File

@ -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());
});
}
/**

View File

@ -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());
});
}
/**

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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);
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();
// 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);
final AuthorizationResult proxyAuthorizationResult = authorizer.authorize(proxyAuthorizationRequest);
if (!Result.Approved.equals(proxyAuthorizationResult.getResult())) {
if (chainIter.hasPrevious()) {
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));

View File

@ -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);
}
}
}

View File

@ -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 {
return currResources.contains(resourceIdentifier);
// 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 {
// 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;
}
}

View File

@ -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 {
@ -193,6 +204,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) {

View File

@ -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

View File

@ -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>"
+ "&lt;tenants&gt;"
+ "&lt;user identifier=\"user-id-1\" identity=\"user-1\"&gt;&lt;/user&gt;"
+ "&lt;group identifier=\"group-id-1\" name=\"group-1\"&gt;"
+ "&lt;groupUser identifier=\"user-id-1\"&gt;&lt;/groupUser&gt;"
+ "&lt;/group&gt;"
+ "&lt;/tenants&gt;"
+ "</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;
}
}

View File

@ -18,52 +18,463 @@
*/
package org.apache.nifi.ranger.authorization;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.AuthorizerConfigurationContext;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.UserAndGroups;
import org.apache.nifi.authorization.UserGroupProvider;
import org.apache.nifi.authorization.UserGroupProviderInitializationContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.model.RangerServiceDef;
import org.apache.ranger.plugin.util.ServicePolicies;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class TestRangerBasePluginWithPolicies {
@Test
public void testDoesPolicyExist() {
final String resourceIdentifier1 = "resource1";
RangerPolicy.RangerPolicyResource resource1 = new RangerPolicy.RangerPolicyResource(resourceIdentifier1);
public void testPoliciesWithoutUserGroupProvider() {
final String user1 = "user-1";
final String group1 = "group-1";
final Map<String, RangerPolicy.RangerPolicyResource> policy1Resources = new HashMap<>();
final String resourceIdentifier1 = "/resource-1";
RangerPolicyResource resource1 = new RangerPolicyResource(resourceIdentifier1);
final Map<String, RangerPolicyResource> policy1Resources = new HashMap<>();
policy1Resources.put(resourceIdentifier1, resource1);
final RangerPolicyItem policy1Item = new RangerPolicyItem();
policy1Item.setAccesses(Stream.of(new RangerPolicyItemAccess("READ")).collect(Collectors.toList()));
policy1Item.setUsers(Stream.of(user1).collect(Collectors.toList()));
final RangerPolicy policy1 = new RangerPolicy();
policy1.setResources(policy1Resources);
policy1.setPolicyItems(Stream.of(policy1Item).collect(Collectors.toList()));
final String resourceIdentifier2 = "resource2";
RangerPolicy.RangerPolicyResource resource2 = new RangerPolicy.RangerPolicyResource(resourceIdentifier2);
final String resourceIdentifier2 = "/resource-2";
RangerPolicyResource resource2 = new RangerPolicyResource(resourceIdentifier2);
final Map<String, RangerPolicy.RangerPolicyResource> policy2Resources = new HashMap<>();
final Map<String, RangerPolicyResource> policy2Resources = new HashMap<>();
policy2Resources.put(resourceIdentifier2, resource2);
final RangerPolicyItem policy2Item = new RangerPolicyItem();
policy2Item.setAccesses(Stream.of(new RangerPolicyItemAccess("READ"), new RangerPolicyItemAccess("WRITE")).collect(Collectors.toList()));
policy2Item.setGroups(Stream.of(group1).collect(Collectors.toList()));
final RangerPolicy policy2 = new RangerPolicy();
policy2.setResources(policy2Resources);
policy2.setPolicyItems(Stream.of(policy2Item).collect(Collectors.toList()));
final List<RangerPolicy> policies = new ArrayList<>();
policies.add(policy1);
policies.add(policy2);
final RangerServiceDef serviceDef = new RangerServiceDef();
serviceDef.setName("nifi");
final ServicePolicies servicePolicies = new ServicePolicies();
servicePolicies.setPolicies(policies);
servicePolicies.setServiceDef(serviceDef);
// set all the policies in the plugin
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi");
pluginWithPolicies.setPolicies(servicePolicies);
Assert.assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier1));
Assert.assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier2));
Assert.assertFalse(pluginWithPolicies.doesPolicyExist("resource3"));
// ensure the two ranger policies converted into 3 nifi access policies
final Set<AccessPolicy> accessPolicies = pluginWithPolicies.getAccessPolicies();
assertEquals(3, accessPolicies.size());
// resource 1 -> read but no write
assertFalse(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.WRITE));
assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.READ));
// read
final AccessPolicy readResource1 = pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.READ);
assertNotNull(readResource1);
assertTrue(accessPolicies.contains(readResource1));
assertTrue(readResource1.equals(pluginWithPolicies.getAccessPolicy(readResource1.getIdentifier())));
assertEquals(1, readResource1.getUsers().size());
assertTrue(readResource1.getUsers().contains(new User.Builder().identifierGenerateFromSeed(user1).identity(user1).build().getIdentifier()));
assertTrue(readResource1.getGroups().isEmpty());
// but no write
assertNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.WRITE));
// resource 2 -> read and write
assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier2, RequestAction.WRITE));
assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier2, RequestAction.READ));
// read
final AccessPolicy readResource2 = pluginWithPolicies.getAccessPolicy(resourceIdentifier2, RequestAction.READ);
assertNotNull(readResource2);
assertTrue(accessPolicies.contains(readResource2));
assertTrue(readResource2.equals(pluginWithPolicies.getAccessPolicy(readResource2.getIdentifier())));
assertTrue(readResource2.getUsers().isEmpty());
assertEquals(1, readResource2.getGroups().size());
assertTrue(readResource2.getGroups().contains(new Group.Builder().identifierGenerateFromSeed(group1).name(group1).build().getIdentifier()));
// and write
final AccessPolicy writeResource2 = pluginWithPolicies.getAccessPolicy(resourceIdentifier2, RequestAction.READ);
assertNotNull(writeResource2);
assertTrue(accessPolicies.contains(writeResource2));
assertTrue(writeResource2.equals(pluginWithPolicies.getAccessPolicy(writeResource2.getIdentifier())));
assertTrue(writeResource2.getUsers().isEmpty());
assertEquals(1, writeResource2.getGroups().size());
assertTrue(writeResource2.getGroups().contains(new Group.Builder().identifierGenerateFromSeed(group1).name(group1).build().getIdentifier()));
// resource 3 -> no read or write
assertFalse(pluginWithPolicies.doesPolicyExist("resource-3", RequestAction.WRITE));
assertFalse(pluginWithPolicies.doesPolicyExist("resource-3", RequestAction.READ));
// no read or write
assertNull(pluginWithPolicies.getAccessPolicy("resource-3", RequestAction.WRITE));
assertNull(pluginWithPolicies.getAccessPolicy("resource-3", RequestAction.READ));
}
@Test
public void testNoPolicies() {
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi");
assertFalse(pluginWithPolicies.doesPolicyExist("non-existent-resource", RequestAction.READ));
assertTrue(pluginWithPolicies.getAccessPolicies().isEmpty());
assertNull(pluginWithPolicies.getAccessPolicy("non-existent-identifier"));
assertNull(pluginWithPolicies.getAccessPolicy("non-existent-resource", RequestAction.READ));
}
@Test
public void testDisabledPolicy() {
final String resourceIdentifier1 = "/resource-1";
RangerPolicyResource resource1 = new RangerPolicyResource(resourceIdentifier1);
final Map<String, RangerPolicyResource> policy1Resources = new HashMap<>();
policy1Resources.put(resourceIdentifier1, resource1);
final RangerPolicyItem policy1Item = new RangerPolicyItem();
policy1Item.setAccesses(Stream.of(new RangerPolicyItemAccess("READ")).collect(Collectors.toList()));
final RangerPolicy policy1 = new RangerPolicy();
policy1.setIsEnabled(false);
policy1.setResources(policy1Resources);
policy1.setPolicyItems(Stream.of(policy1Item).collect(Collectors.toList()));
final List<RangerPolicy> policies = new ArrayList<>();
policies.add(policy1);
final RangerServiceDef serviceDef = new RangerServiceDef();
serviceDef.setName("nifi");
final ServicePolicies servicePolicies = new ServicePolicies();
servicePolicies.setPolicies(policies);
servicePolicies.setServiceDef(serviceDef);
// set all the policies in the plugin
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi");
pluginWithPolicies.setPolicies(servicePolicies);
// ensure the policy was skipped
assertFalse(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.READ));
assertTrue(pluginWithPolicies.getAccessPolicies().isEmpty());
assertNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.READ));
}
@Test
public void testExcludesPolicy() {
final String resourceIdentifier1 = "/resource-1";
RangerPolicyResource resource1 = new RangerPolicyResource(resourceIdentifier1);
resource1.setIsExcludes(true);
final Map<String, RangerPolicyResource> policy1Resources = new HashMap<>();
policy1Resources.put(resourceIdentifier1, resource1);
final RangerPolicyItem policy1Item = new RangerPolicyItem();
policy1Item.setAccesses(Stream.of(new RangerPolicyItemAccess("WRITE")).collect(Collectors.toList()));
final RangerPolicy policy1 = new RangerPolicy();
policy1.setResources(policy1Resources);
policy1.setPolicyItems(Stream.of(policy1Item).collect(Collectors.toList()));
final List<RangerPolicy> policies = new ArrayList<>();
policies.add(policy1);
final RangerServiceDef serviceDef = new RangerServiceDef();
serviceDef.setName("nifi");
final ServicePolicies servicePolicies = new ServicePolicies();
servicePolicies.setPolicies(policies);
servicePolicies.setServiceDef(serviceDef);
// set all the policies in the plugin
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi");
pluginWithPolicies.setPolicies(servicePolicies);
// ensure the policy was skipped
assertFalse(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.WRITE));
assertTrue(pluginWithPolicies.getAccessPolicies().isEmpty());
assertNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.WRITE));
}
@Test
public void testRecursivePolicy() {
final String resourceIdentifier1 = "/resource-1";
RangerPolicyResource resource1 = new RangerPolicyResource(resourceIdentifier1);
resource1.setIsRecursive(true);
final Map<String, RangerPolicyResource> policy1Resources = new HashMap<>();
policy1Resources.put(resourceIdentifier1, resource1);
final RangerPolicyItem policy1Item = new RangerPolicyItem();
policy1Item.setAccesses(Stream.of(new RangerPolicyItemAccess("WRITE")).collect(Collectors.toList()));
final RangerPolicy policy1 = new RangerPolicy();
policy1.setResources(policy1Resources);
policy1.setPolicyItems(Stream.of(policy1Item).collect(Collectors.toList()));
final List<RangerPolicy> policies = new ArrayList<>();
policies.add(policy1);
final RangerServiceDef serviceDef = new RangerServiceDef();
serviceDef.setName("nifi");
final ServicePolicies servicePolicies = new ServicePolicies();
servicePolicies.setPolicies(policies);
servicePolicies.setServiceDef(serviceDef);
// set all the policies in the plugin
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi");
pluginWithPolicies.setPolicies(servicePolicies);
// ensure the policy was skipped
assertFalse(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.WRITE));
assertTrue(pluginWithPolicies.getAccessPolicies().isEmpty());
assertNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.WRITE));
}
@Test
public void testDelegateAdmin() {
final String user1 = "user-1";
final String resourceIdentifier1 = "/resource-1";
RangerPolicyResource resource1 = new RangerPolicyResource(resourceIdentifier1);
final Map<String, RangerPolicyResource> policy1Resources = new HashMap<>();
policy1Resources.put(resourceIdentifier1, resource1);
final RangerPolicyItem policy1Item = new RangerPolicyItem();
policy1Item.setAccesses(Stream.of(new RangerPolicyItemAccess("READ"), new RangerPolicyItemAccess("WRITE")).collect(Collectors.toList()));
policy1Item.setUsers(Stream.of(user1).collect(Collectors.toList()));
policy1Item.setDelegateAdmin(true);
final RangerPolicy policy1 = new RangerPolicy();
policy1.setResources(policy1Resources);
policy1.setPolicyItems(Stream.of(policy1Item).collect(Collectors.toList()));
final List<RangerPolicy> policies = new ArrayList<>();
policies.add(policy1);
final RangerServiceDef serviceDef = new RangerServiceDef();
serviceDef.setName("nifi");
final ServicePolicies servicePolicies = new ServicePolicies();
servicePolicies.setPolicies(policies);
servicePolicies.setServiceDef(serviceDef);
// set all the policies in the plugin
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi");
pluginWithPolicies.setPolicies(servicePolicies);
assertEquals(4, pluginWithPolicies.getAccessPolicies().size());
assertNotNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.READ));
assertNotNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.WRITE));
assertNotNull(pluginWithPolicies.getAccessPolicy("/policies" + resourceIdentifier1, RequestAction.READ));
assertNotNull(pluginWithPolicies.getAccessPolicy("/policies" + resourceIdentifier1, RequestAction.WRITE));
}
@Test
public void testPoliciesWithUserGroupProvider() {
final String user1 = "user-1"; // unknown according to user group provider
final String user2 = "user-2"; // known according to user group provider
final String group1 = "group-1"; // unknown according to user group provider
final String group2 = "group-2"; // known according to user group provider
final UserGroupProvider userGroupProvider = new UserGroupProvider() {
@Override
public Set<User> getUsers() throws AuthorizationAccessException {
return Stream.of(new User.Builder().identifierGenerateFromSeed(user2).identity(user2).build()).collect(Collectors.toSet());
}
@Override
public User getUser(String identifier) throws AuthorizationAccessException {
final User u2 = new User.Builder().identifierGenerateFromSeed(user2).identity(user2).build();
if (u2.getIdentifier().equals(identifier)) {
return u2;
} else {
return null;
}
}
@Override
public User getUserByIdentity(String identity) throws AuthorizationAccessException {
if (user2.equals(identity)) {
return new User.Builder().identifierGenerateFromSeed(user2).identity(user2).build();
} else {
return null;
}
}
@Override
public Set<Group> getGroups() throws AuthorizationAccessException {
return Stream.of(new Group.Builder().identifierGenerateFromSeed(group2).name(group2).build()).collect(Collectors.toSet());
}
@Override
public Group getGroup(String identifier) throws AuthorizationAccessException {
final Group g2 = new Group.Builder().identifierGenerateFromSeed(group2).name(group2).build();
if (g2.getIdentifier().equals(identifier)) {
return g2;
} else {
return null;
}
}
@Override
public UserAndGroups getUserAndGroups(String identity) throws AuthorizationAccessException {
if (user2.equals(identity)) {
return new UserAndGroups() {
@Override
public User getUser() {
return new User.Builder().identifierGenerateFromSeed(user2).identity(user2).build();
}
@Override
public Set<Group> getGroups() {
return Collections.EMPTY_SET;
}
};
} else {
return null;
}
}
@Override
public void initialize(UserGroupProviderInitializationContext initializationContext) throws AuthorizerCreationException {
}
@Override
public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
}
@Override
public void preDestruction() throws AuthorizerDestructionException {
}
};
final String resourceIdentifier1 = "/resource-1";
RangerPolicyResource resource1 = new RangerPolicyResource(resourceIdentifier1);
final Map<String, RangerPolicyResource> policy1Resources = new HashMap<>();
policy1Resources.put(resourceIdentifier1, resource1);
final RangerPolicyItem policy1Item = new RangerPolicyItem();
policy1Item.setAccesses(Stream.of(new RangerPolicyItemAccess("READ")).collect(Collectors.toList()));
policy1Item.setUsers(Stream.of(user1).collect(Collectors.toList()));
policy1Item.setGroups(Stream.of(group2).collect(Collectors.toList()));
final RangerPolicy policy1 = new RangerPolicy();
policy1.setResources(policy1Resources);
policy1.setPolicyItems(Stream.of(policy1Item).collect(Collectors.toList()));
final String resourceIdentifier2 = "/resource-2";
RangerPolicyResource resource2 = new RangerPolicyResource(resourceIdentifier2);
final Map<String, RangerPolicyResource> policy2Resources = new HashMap<>();
policy2Resources.put(resourceIdentifier2, resource2);
final RangerPolicyItem policy2Item = new RangerPolicyItem();
policy2Item.setAccesses(Stream.of(new RangerPolicyItemAccess("READ"), new RangerPolicyItemAccess("WRITE")).collect(Collectors.toList()));
policy2Item.setUsers(Stream.of(user2).collect(Collectors.toList()));
policy2Item.setGroups(Stream.of(group1).collect(Collectors.toList()));
final RangerPolicy policy2 = new RangerPolicy();
policy2.setResources(policy2Resources);
policy2.setPolicyItems(Stream.of(policy2Item).collect(Collectors.toList()));
final List<RangerPolicy> policies = new ArrayList<>();
policies.add(policy1);
policies.add(policy2);
final RangerServiceDef serviceDef = new RangerServiceDef();
serviceDef.setName("nifi");
final ServicePolicies servicePolicies = new ServicePolicies();
servicePolicies.setPolicies(policies);
servicePolicies.setServiceDef(serviceDef);
// set all the policies in the plugin
final RangerBasePluginWithPolicies pluginWithPolicies = new RangerBasePluginWithPolicies("nifi", "nifi", userGroupProvider);
pluginWithPolicies.setPolicies(servicePolicies);
// ensure the two ranger policies converted into 3 nifi access policies
final Set<AccessPolicy> accessPolicies = pluginWithPolicies.getAccessPolicies();
assertEquals(3, accessPolicies.size());
// resource 1 -> read but no write
assertFalse(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.WRITE));
assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier1, RequestAction.READ));
// read
final AccessPolicy readResource1 = pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.READ);
assertNotNull(readResource1);
assertTrue(accessPolicies.contains(readResource1));
assertTrue(readResource1.equals(pluginWithPolicies.getAccessPolicy(readResource1.getIdentifier())));
assertTrue(readResource1.getUsers().isEmpty());
assertEquals(1, readResource1.getGroups().size());
assertTrue(readResource1.getGroups().contains(new Group.Builder().identifierGenerateFromSeed(group2).name(group2).build().getIdentifier()));
// but no write
assertNull(pluginWithPolicies.getAccessPolicy(resourceIdentifier1, RequestAction.WRITE));
// resource 2 -> read and write
assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier2, RequestAction.WRITE));
assertTrue(pluginWithPolicies.doesPolicyExist(resourceIdentifier2, RequestAction.READ));
// read
final AccessPolicy readResource2 = pluginWithPolicies.getAccessPolicy(resourceIdentifier2, RequestAction.READ);
assertNotNull(readResource2);
assertTrue(accessPolicies.contains(readResource2));
assertTrue(readResource2.equals(pluginWithPolicies.getAccessPolicy(readResource2.getIdentifier())));
assertEquals(1, readResource2.getUsers().size());
assertTrue(readResource2.getUsers().contains(new User.Builder().identifierGenerateFromSeed(user2).identity(user2).build().getIdentifier()));
assertTrue(readResource2.getGroups().isEmpty());
// and write
final AccessPolicy writeResource2 = pluginWithPolicies.getAccessPolicy(resourceIdentifier2, RequestAction.READ);
assertNotNull(writeResource2);
assertTrue(accessPolicies.contains(writeResource2));
assertTrue(writeResource2.equals(pluginWithPolicies.getAccessPolicy(writeResource2.getIdentifier())));
assertEquals(1, writeResource2.getUsers().size());
assertTrue(writeResource2.getUsers().contains(new User.Builder().identifierGenerateFromSeed(user2).identity(user2).build().getIdentifier()));
assertTrue(writeResource2.getGroups().isEmpty());
}
}

View File

@ -261,8 +261,7 @@ public class TestRangerNiFiAuthorizer {
// a non-null result processor should be used for direct access
when(rangerBasePlugin.isAccessAllowed(
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)),
notNull(RangerAccessResultProcessor.class))
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)))
).thenReturn(allowedResult);
final AuthorizationResult result = authorizer.authorize(request);
@ -297,8 +296,7 @@ public class TestRangerNiFiAuthorizer {
// no result processor should be provided used non-direct access
when(rangerBasePlugin.isAccessAllowed(
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)),
eq(null))
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)))
).thenReturn(allowedResult);
final AuthorizationResult result = authorizer.authorize(request);
@ -338,7 +336,7 @@ public class TestRangerNiFiAuthorizer {
).thenReturn(notAllowedResult);
// return false when checking if a policy exists for the resource
when(rangerBasePlugin.doesPolicyExist(systemResource)).thenReturn(false);
when(rangerBasePlugin.doesPolicyExist(systemResource, action)).thenReturn(false);
final AuthorizationResult result = authorizer.authorize(request);
assertEquals(AuthorizationResult.resourceNotFound().getResult(), result.getResult());
@ -372,12 +370,11 @@ public class TestRangerNiFiAuthorizer {
// no result processor should be provided used non-direct access
when(rangerBasePlugin.isAccessAllowed(
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)),
notNull(RangerAccessResultProcessor.class))
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)))
).thenReturn(notAllowedResult);
// return true when checking if a policy exists for the resource
when(rangerBasePlugin.doesPolicyExist(systemResource)).thenReturn(true);
when(rangerBasePlugin.doesPolicyExist(systemResource, action)).thenReturn(true);
final AuthorizationResult result = authorizer.authorize(request);
assertEquals(AuthorizationResult.denied().getResult(), result.getResult());
@ -427,12 +424,11 @@ public class TestRangerNiFiAuthorizer {
expectedRangerRequest.setUser(request.getIdentity());
// return true when checking if a policy exists for the resource
when(rangerBasePlugin.doesPolicyExist(resourceIdentifier)).thenReturn(true);
when(rangerBasePlugin.doesPolicyExist(resourceIdentifier, action)).thenReturn(true);
// a non-null result processor should be used for direct access
when(rangerBasePlugin.isAccessAllowed(
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)),
notNull(RangerAccessResultProcessor.class))
argThat(new RangerAccessRequestMatcher(expectedRangerRequest)))
).thenReturn(notAllowedResult);
final AuthorizationResult result = authorizer.authorize(request);

View File

@ -101,7 +101,7 @@
<hadoop.guava.version>12.0.1</hadoop.guava.version>
<hadoop.http.client.version>4.2.5</hadoop.http.client.version>
<yammer.metrics.version>2.2.0</yammer.metrics.version>
<ranger.version>0.6.0</ranger.version>
<ranger.version>0.7.1</ranger.version>
<hive.version>1.2.1</hive.version>
<hive.hadoop.version>2.6.2</hive.hadoop.version>
<hbase.version>1.1.2</hbase.version>