Skip to content

Commit

Permalink
NIFI-4032:
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
mcgilman committed Jul 19, 2017
1 parent 844dbe4 commit a65cf58
Show file tree
Hide file tree
Showing 33 changed files with 1,345 additions and 841 deletions.
@@ -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);
}
Expand Up @@ -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;
Expand Down Expand Up @@ -64,6 +65,12 @@ private AuthorizationRequest(final Builder builder) {
return explanation;
}
};

if (builder.requestedResource == null) {
this.requestedResource = builder.resource;
} else {
this.requestedResource = builder.requestedResource;
}
}

/**
Expand All @@ -75,6 +82,17 @@ public Resource getResource() {
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.
*
Expand Down Expand Up @@ -154,6 +172,7 @@ public Supplier<String> getExplanationSupplier() {
public static final class Builder {

private Resource resource;
private Resource requestedResource;
private String identity;
private Set<String> groups;
private Boolean isAnonymous;
Expand All @@ -168,6 +187,11 @@ public Builder resource(final Resource resource) {
return this;
}

public Builder requestedResource(final Resource requestedResource) {
this.requestedResource = requestedResource;
return this;
}

public Builder identity(final String identity) {
this.identity = identity;
return this;
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -82,13 +94,15 @@ default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAct
}

final Resource resource = getResource();
final Resource requestedResource = getRequestedResource();
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity(user.getIdentity())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(false)
.action(action)
.resource(resource)
.requestedResource(requestedResource)
.resourceContext(resourceContext)
.userContext(userContext)
.explanationSupplier(() -> {
Expand Down Expand Up @@ -122,6 +136,11 @@ public Authorizable getParentAuthorizable() {
return parent.getParentAuthorizable();
}

@Override
public Resource getRequestedResource() {
return requestedResource;
}

@Override
public Resource getResource() {
final Resource parentResource = parent.getResource();
Expand Down Expand Up @@ -187,13 +206,15 @@ default void authorize(Authorizer authorizer, RequestAction action, NiFiUser use
}

final Resource resource = getResource();
final Resource requestedResource = getRequestedResource();
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.identity(user.getIdentity())
.groups(user.getGroups())
.anonymous(user.isAnonymous())
.accessAttempt(true)
.action(action)
.resource(resource)
.requestedResource(requestedResource)
.resourceContext(resourceContext)
.userContext(userContext)
.explanationSupplier(() -> {
Expand All @@ -215,7 +236,15 @@ default void authorize(Authorizer authorizer, RequestAction action, NiFiUser use
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() {
Expand All @@ -224,6 +253,11 @@ public Authorizable getParentAuthorizable() {
return parent.getParentAuthorizable();
}

@Override
public Resource getRequestedResource() {
return requestedResource;
}

@Override
public Resource getResource() {
final Resource parentResource = parent.getResource();
Expand Down
Expand Up @@ -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() {}
Expand Down

0 comments on commit a65cf58

Please sign in to comment.