mirror of https://github.com/apache/nifi.git
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:
parent
10692256d6
commit
743c6b9c17
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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() {}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
return currResources.contains(resourceIdentifier);
|
||||
adminResource = "/policies/" + resource;
|
||||
}
|
||||
|
||||
final AccessPolicy adminAccessPolicy = createPolicy.apply(adminResource);
|
||||
policiesByIdentifier.put(adminAccessPolicy.getIdentifier(), adminAccessPolicy);
|
||||
policiesByResource.computeIfAbsent(adminResource, ar -> new HashMap<>()).put(action, adminAccessPolicy);
|
||||
}
|
||||
});
|
||||
} catch (final IllegalArgumentException e) {
|
||||
logger.warn(String.format("Unrecognized request action '%s'. Skipping policy for viewing purposes. Will still be used for access decisions.", access.getType()));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return new PolicyLookup(policiesByIdentifier, policiesByResource);
|
||||
}
|
||||
|
||||
private User getUser(final String identity) {
|
||||
if (userGroupProvider == null) {
|
||||
// generate the user deterministically when running outside of the ManagedRangerAuthorizer
|
||||
return new User.Builder().identifierGenerateFromSeed(identity).identity(identity).build();
|
||||
} else {
|
||||
// find the user in question
|
||||
final User user = userGroupProvider.getUserByIdentity(identity);
|
||||
|
||||
if (user == null) {
|
||||
logger.warn(String.format("Cannot find user '%s' in the configured User Group Provider. Skipping user for viewing purposes. Will still be used for access decisions.", identity));
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
private Group getGroup(final String name) {
|
||||
if (userGroupProvider == null) {
|
||||
// generate the group deterministically when running outside of the ManagedRangerAuthorizer
|
||||
return new Group.Builder().identifierGenerateFromSeed(name).name(name).build();
|
||||
} else {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.nifi.ranger.authorization;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.nifi.authorization.AuthorizerConfigurationContext;
|
||||
import org.apache.nifi.authorization.AuthorizerInitializationContext;
|
||||
import org.apache.nifi.authorization.ConfigurableUserGroupProvider;
|
||||
import org.apache.nifi.authorization.UserGroupProvider;
|
||||
import org.apache.nifi.authorization.UserGroupProviderLookup;
|
||||
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
|
||||
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
|
||||
import org.apache.nifi.util.MockPropertyValue;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ManagedRangerAuthorizerTest {
|
||||
|
||||
private static final String TENANT_FINGERPRINT =
|
||||
"<tenants>"
|
||||
+ "<user identifier=\"user-id-1\" identity=\"user-1\"></user>"
|
||||
+ "<group identifier=\"group-id-1\" name=\"group-1\">"
|
||||
+ "<groupUser identifier=\"user-id-1\"></groupUser>"
|
||||
+ "</group>"
|
||||
+ "</tenants>";
|
||||
|
||||
private static final String EMPTY_FINGERPRINT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||
+ "<managedRangerAuthorizations>"
|
||||
+ "<userGroupProvider/>"
|
||||
+ "</managedRangerAuthorizations>";
|
||||
|
||||
private static final String NON_EMPTY_FINGERPRINT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||
+ "<managedRangerAuthorizations>"
|
||||
+ "<userGroupProvider>"
|
||||
+ "<tenants>"
|
||||
+ "<user identifier=\"user-id-1\" identity=\"user-1\"></user>"
|
||||
+ "<group identifier=\"group-id-1\" name=\"group-1\">"
|
||||
+ "<groupUser identifier=\"user-id-1\"></groupUser>"
|
||||
+ "</group>"
|
||||
+ "</tenants>"
|
||||
+ "</userGroupProvider>"
|
||||
+ "</managedRangerAuthorizations>";
|
||||
|
||||
private final String serviceType = "nifiService";
|
||||
private final String appId = "nifiAppId";
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
// have to initialize this system property before anything else
|
||||
File krb5conf = new File("src/test/resources/krb5.conf");
|
||||
assertTrue(krb5conf.exists());
|
||||
System.setProperty("java.security.krb5.conf", krb5conf.getAbsolutePath());
|
||||
|
||||
// rest the authentication to simple in case any tests set it to kerberos
|
||||
final Configuration securityConf = new Configuration();
|
||||
securityConf.set(RangerNiFiAuthorizer.HADOOP_SECURITY_AUTHENTICATION, "simple");
|
||||
UserGroupInformation.setConfiguration(securityConf);
|
||||
|
||||
assertFalse(UserGroupInformation.isSecurityEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonConfigurableFingerPrint() throws Exception {
|
||||
final UserGroupProvider userGroupProvider = mock(UserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
Assert.assertEquals(EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurableEmptyFingerPrint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
when(userGroupProvider.getFingerprint()).thenReturn("");
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
Assert.assertEquals(EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurableFingerPrint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
when(userGroupProvider.getFingerprint()).thenReturn(TENANT_FINGERPRINT);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
Assert.assertEquals(NON_EMPTY_FINGERPRINT, managedRangerAuthorizer.getFingerprint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritEmptyFingerprint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.inheritFingerprint(EMPTY_FINGERPRINT);
|
||||
|
||||
verify(userGroupProvider, times(0)).inheritFingerprint(anyString());
|
||||
}
|
||||
|
||||
@Test(expected = AuthorizationAccessException.class)
|
||||
public void testInheritInvalidFingerprint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.inheritFingerprint("not a valid fingerprint");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritNonEmptyFingerprint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.inheritFingerprint(NON_EMPTY_FINGERPRINT);
|
||||
|
||||
verify(userGroupProvider, times(1)).inheritFingerprint(TENANT_FINGERPRINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInheritEmptyFingerprint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.checkInheritability(EMPTY_FINGERPRINT);
|
||||
|
||||
verify(userGroupProvider, times(0)).inheritFingerprint(anyString());
|
||||
}
|
||||
|
||||
@Test(expected = AuthorizationAccessException.class)
|
||||
public void testCheckInheritInvalidFingerprint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.checkInheritability("not a valid fingerprint");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckInheritNonEmptyFingerprint() throws Exception {
|
||||
final ConfigurableUserGroupProvider userGroupProvider = mock(ConfigurableUserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.checkInheritability(NON_EMPTY_FINGERPRINT);
|
||||
|
||||
verify(userGroupProvider, times(1)).checkInheritability(TENANT_FINGERPRINT);
|
||||
}
|
||||
|
||||
@Test(expected = UninheritableAuthorizationsException.class)
|
||||
public void testCheckInheritNonConfigurableUserGroupProvider() throws Exception {
|
||||
final UserGroupProvider userGroupProvider = mock(UserGroupProvider.class);
|
||||
|
||||
final ManagedRangerAuthorizer managedRangerAuthorizer = getStandardManagedAuthorizer(userGroupProvider);
|
||||
managedRangerAuthorizer.checkInheritability(NON_EMPTY_FINGERPRINT);
|
||||
}
|
||||
|
||||
private ManagedRangerAuthorizer getStandardManagedAuthorizer(final UserGroupProvider userGroupProvider) {
|
||||
final ManagedRangerAuthorizer managedAuthorizer = new ManagedRangerAuthorizer();
|
||||
|
||||
final AuthorizerConfigurationContext configurationContext = mock(AuthorizerConfigurationContext.class);
|
||||
when(configurationContext.getProperty(eq("User Group Provider"))).thenReturn(new MockPropertyValue("user-group-provider", null));
|
||||
when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_SECURITY_PATH_PROP))).thenReturn(new MockPropertyValue("src/test/resources/ranger/ranger-nifi-security.xml"));
|
||||
when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_AUDIT_PATH_PROP))).thenReturn(new MockPropertyValue("src/test/resources/ranger/ranger-nifi-audit.xml"));
|
||||
when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_APP_ID_PROP))).thenReturn(new MockPropertyValue(appId));
|
||||
when(configurationContext.getProperty(eq(RangerNiFiAuthorizer.RANGER_SERVICE_TYPE_PROP))).thenReturn(new MockPropertyValue(serviceType));
|
||||
|
||||
final UserGroupProviderLookup userGroupProviderLookup = mock(UserGroupProviderLookup.class);
|
||||
when(userGroupProviderLookup.getUserGroupProvider("user-group-provider")).thenReturn(userGroupProvider);
|
||||
|
||||
final AuthorizerInitializationContext initializationContext = mock(AuthorizerInitializationContext.class);
|
||||
when(initializationContext.getUserGroupProviderLookup()).thenReturn(userGroupProviderLookup);
|
||||
|
||||
managedAuthorizer.initialize(initializationContext);
|
||||
managedAuthorizer.onConfigured(configurationContext);
|
||||
|
||||
return managedAuthorizer;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue