blob: 2cc03f88b5ac7cd650c271053304cba7fe33e4dd [file] [log] [blame]
/*
* 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.registry.security.authorization;
import org.apache.nifi.registry.bucket.Bucket;
import org.apache.nifi.registry.security.authorization.resource.ResourceFactory;
import org.apache.nifi.registry.service.RegistryService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import java.util.Arrays;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
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 TestFrameworkAuthorizer {
private Authorizer frameworkAuthorizer;
private Authorizer wrappedAuthorizer;
private RegistryService registryService;
private Bucket bucketPublic;
private Bucket bucketNotPublic;
@Before
public void setup() {
wrappedAuthorizer = mock(Authorizer.class);
registryService = mock(RegistryService.class);
frameworkAuthorizer = new FrameworkAuthorizer(wrappedAuthorizer, registryService);
bucketPublic = new Bucket();
bucketPublic.setIdentifier(UUID.randomUUID().toString());
bucketPublic.setName("Public Bucket");
bucketPublic.setAllowPublicRead(true);
bucketNotPublic = new Bucket();
bucketNotPublic.setIdentifier(UUID.randomUUID().toString());
bucketNotPublic.setName("Non Public Bucket");
bucketNotPublic.setAllowPublicRead(false);
when(registryService.getBucket(bucketPublic.getIdentifier())).thenReturn(bucketPublic);
when(registryService.getBucket(bucketNotPublic.getIdentifier())).thenReturn(bucketNotPublic);
}
@Test
public void testReadPublicBucketWhenAnonymous() {
final Resource resource = ResourceFactory.getBucketResource(bucketPublic.getIdentifier(), bucketPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.READ)
.accessAttempt(true)
.identity("anonymous")
.anonymous(true)
.build();
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Approved, result.getResult());
// should never make it to wrapped authorizer
verify(wrappedAuthorizer, times(0)).authorize(any(AuthorizationRequest.class));
}
@Test
public void testReadNonPublicBucketWhenAnonymous() {
final Resource resource = ResourceFactory.getBucketResource(bucketNotPublic.getIdentifier(), bucketNotPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.READ)
.accessAttempt(true)
.identity("anonymous")
.anonymous(true)
.build();
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Denied, result.getResult());
// should be denied before making it to the wrapped authorizer since the user is anonymous
verify(wrappedAuthorizer, times(0)).authorize(any(AuthorizationRequest.class));
}
@Test
public void testWritePublicBucketWhenAnonymous() {
final Resource resource = ResourceFactory.getBucketResource(bucketPublic.getIdentifier(), bucketPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.WRITE)
.accessAttempt(true)
.identity("anonymous")
.anonymous(true)
.build();
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Denied, result.getResult());
// should be denied before making it to wrapped authorizer since request is anonymous
verify(wrappedAuthorizer, times(0)).authorize(any(AuthorizationRequest.class));
}
@Test
public void testReadPublicBucketWhenNotAnonymous() {
final Resource resource = ResourceFactory.getBucketResource(bucketPublic.getIdentifier(), bucketPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.READ)
.accessAttempt(true)
.identity("user1")
.anonymous(false)
.proxyIdentities(Arrays.asList("proxy1", "proxy2"))
.build();
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Approved, result.getResult());
// should never make it to wrapped authorizer
verify(wrappedAuthorizer, times(0)).authorize(any(AuthorizationRequest.class));
}
@Test
public void testReadNonPublicBucketWhenNotAnonymousAndAuthorizedProxies() {
final Resource resource = ResourceFactory.getBucketResource(bucketNotPublic.getIdentifier(), bucketNotPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.READ)
.accessAttempt(true)
.identity("user1")
.anonymous(false)
.proxyIdentities(Arrays.asList("proxy1", "proxy2"))
.build();
// since the bucket is not public it will fall through to the wrapped authorizer
when(wrappedAuthorizer.authorize(any(AuthorizationRequest.class)))
.thenReturn(AuthorizationResult.approved());
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Approved, result.getResult());
// should make 3 calls to the wrapped authorizer to authorize user1, proxy1, proxy2
verify(wrappedAuthorizer, times(3)).authorize(any(AuthorizationRequest.class));
}
@Test
public void testReadNonPublicBucketWhenNotAnonymousAndUnauthorizedProxy() {
final Resource resource = ResourceFactory.getBucketResource(bucketNotPublic.getIdentifier(), bucketNotPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.READ)
.accessAttempt(true)
.identity("user1")
.anonymous(false)
.proxyIdentities(Arrays.asList("proxy1", "proxy2"))
.build();
// since the bucket is not public and the user is not anonymous, it will continue to proxy authorization
// simulate the first proxy being authorized for READ actions
final AuthorizationRequestMatcher proxy1Matcher = new AuthorizationRequestMatcher(
"proxy1", ResourceFactory.getProxyResource(), request.getAction());
when(wrappedAuthorizer.authorize(argThat(proxy1Matcher))).thenReturn(AuthorizationResult.approved());
// simulate the second proxy being unauthorized for READ actions
final AuthorizationRequestMatcher proxy2Matcher = new AuthorizationRequestMatcher(
"proxy2", ResourceFactory.getProxyResource(), request.getAction());
when(wrappedAuthorizer.authorize(argThat(proxy2Matcher))).thenReturn(AuthorizationResult.denied("denied"));
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Denied, result.getResult());
// should make 2 calls to the wrapped authorizer for the two proxies
verify(wrappedAuthorizer, times(2)).authorize(any(AuthorizationRequest.class));
}
@Test
public void testReadNonPublicBucketWhenNotAnonymousAndUnauthorizedEndUser() {
final Resource resource = ResourceFactory.getBucketResource(bucketNotPublic.getIdentifier(), bucketNotPublic.getName());
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(resource)
.requestedResource(resource)
.action(RequestAction.READ)
.accessAttempt(true)
.identity("user1")
.anonymous(false)
.proxyIdentities(Arrays.asList("proxy1", "proxy2"))
.build();
// since the bucket is not public and the user is not anonymous, it will continue to proxy authorization
// simulate the first proxy being authorized for READ actions
final AuthorizationRequestMatcher proxy1Matcher = new AuthorizationRequestMatcher(
"proxy1", ResourceFactory.getProxyResource(), request.getAction());
when(wrappedAuthorizer.authorize(argThat(proxy1Matcher))).thenReturn(AuthorizationResult.approved());
// simulate the second proxy being authorized for READ actions
final AuthorizationRequestMatcher proxy2Matcher = new AuthorizationRequestMatcher(
"proxy2", ResourceFactory.getProxyResource(), request.getAction());
when(wrappedAuthorizer.authorize(argThat(proxy2Matcher))).thenReturn(AuthorizationResult.approved());
// simulate the end user being unauthorized for READ actions
final AuthorizationRequestMatcher user1Matcher = new AuthorizationRequestMatcher(
"user1", resource, request.getAction());
when(wrappedAuthorizer.authorize(argThat(user1Matcher))).thenReturn(AuthorizationResult.denied("denied"));
final AuthorizationResult result = frameworkAuthorizer.authorize(request);
assertNotNull(result);
assertEquals(AuthorizationResult.Result.Denied, result.getResult());
// should make 3 calls to the wrapped authorizer for the two proxies and end user
verify(wrappedAuthorizer, times(3)).authorize(any(AuthorizationRequest.class));
}
/**
* Matcher for matching Authorization requests.
*/
private static class AuthorizationRequestMatcher implements ArgumentMatcher<AuthorizationRequest> {
private final String identity;
private final Resource resource;
private final RequestAction action;
public AuthorizationRequestMatcher(final String identity, final Resource resource, final RequestAction action) {
this.identity = identity;
this.resource = resource;
this.action = action;
}
@Override
public boolean matches(final AuthorizationRequest request) {
if (request == null) {
return false;
}
return identity.equals(request.getIdentity())
&& resource.getIdentifier().equals(request.getResource().getIdentifier())
&& action == request.getAction();
}
}
}