Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@
import org.apache.hadoop.ozone.om.OmSnapshot;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.PrefixManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Creates {@link IAccessAuthorizer} instances based on configuration.
*/
public final class OzoneAuthorizerFactory {
static final Logger LOG = LoggerFactory.getLogger(OzoneAuthorizerFactory.class);

private OzoneAuthorizerFactory() {
// no instances
Expand All @@ -42,7 +45,7 @@ private OzoneAuthorizerFactory() {
* @return authorizer instance for {@link OzoneManager}
*/
public static IAccessAuthorizer forOM(OzoneManager om) {
return create(om, om.getKeyManager(), om.getPrefixManager());
return create(om, om.getKeyManager(), om.getPrefixManager(), "OM");
}

/**
Expand All @@ -53,17 +56,21 @@ public static IAccessAuthorizer forSnapshot(
OzoneManager om, KeyManager keyManager, PrefixManager prefixManager
) {
return om.getAccessAuthorizer().isNative()
? create(om, keyManager, prefixManager)
? create(om, keyManager, prefixManager, "Snapshot")
: om.getAccessAuthorizer();
}

/**
* Creates new instance (except for {@link OzoneAccessAuthorizer},
* which is a no-op authorizer.
*/
private static IAccessAuthorizer create(
OzoneManager om, KeyManager km, PrefixManager pm
) {
private static IAccessAuthorizer create(OzoneManager om, KeyManager km, PrefixManager pm, String name) {
final IAccessAuthorizer authorizer = createImpl(om, km, pm);
LOG.info("{}: Authorizer for {} is {}", om.getOMNodeId(), name, authorizer.getClass());
return authorizer;
}

private static IAccessAuthorizer createImpl(OzoneManager om, KeyManager km, PrefixManager pm) {
if (!om.getAclsEnabled()) {
return OzoneAccessAuthorizer.get();
}
Expand All @@ -76,46 +83,27 @@ private static IAccessAuthorizer create(
}

if (OzoneNativeAuthorizer.class == clazz) {
final OzoneNativeAuthorizer authorizer = new OzoneNativeAuthorizer();
return configure(authorizer, om, km, pm);
return new OzoneNativeAuthorizer().configure(om, km, pm);
}

final IAccessAuthorizer authorizer = newInstance(clazz, conf);

if (authorizer instanceof OzoneNativeAuthorizer) {
return configure((OzoneNativeAuthorizer) authorizer, om, km, pm);
if (authorizer instanceof OzoneManagerAuthorizer) {
return ((OzoneManagerAuthorizer) authorizer).configure(om, km, pm);
}

// If authorizer isn't native and shareable tmp dir is enabled,
// then return the shared tmp hybrid authorizer.
if (conf.getBoolean(OZONE_OM_ENABLE_OFS_SHARED_TMP_DIR,
OZONE_OM_ENABLE_OFS_SHARED_TMP_DIR_DEFAULT)) {
return new SharedTmpDirAuthorizer(
configure(new OzoneNativeAuthorizer(), om, km, pm),
new OzoneNativeAuthorizer().configure(om, km, pm),
authorizer);
}

return authorizer;
}

/**
* Configure {@link OzoneNativeAuthorizer}.
* @return same instance for convenience
*/
private static OzoneNativeAuthorizer configure(
OzoneNativeAuthorizer authorizer,
OzoneManager om, KeyManager km, PrefixManager pm
) {
authorizer.setVolumeManager(om.getVolumeManager());
authorizer.setBucketManager(om.getBucketManager());
authorizer.setKeyManager(km);
authorizer.setPrefixManager(pm);
authorizer.setAdminCheck(om::isAdmin);
authorizer.setReadOnlyAdminCheck(om::isReadOnlyAdmin);
authorizer.setAllowListAllVolumes(om::getAllowListAllVolumes);
return authorizer;
}

private static Class<? extends IAccessAuthorizer> authorizerClass(
ConfigurationSource conf) {
return conf.getClass(OZONE_ACL_AUTHORIZER_CLASS,
Expand Down
Original file line number Diff line number Diff line change
@@ -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.hadoop.ozone.security.acl;

import org.apache.hadoop.ozone.om.KeyManager;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.PrefixManager;

/**
* A subinterface of {@link IAccessAuthorizer} specifically for Ozone Manager.
*/
public interface OzoneManagerAuthorizer extends IAccessAuthorizer {
/** Configure this authorizer. */
OzoneManagerAuthorizer configure(OzoneManager om, KeyManager km, PrefixManager pm);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.INVALID_REQUEST;

import com.google.common.annotations.VisibleForTesting;
import java.util.Objects;
import java.util.function.BooleanSupplier;
import java.util.function.Predicate;
Expand All @@ -30,6 +29,7 @@
import org.apache.hadoop.ozone.om.BucketManager;
import org.apache.hadoop.ozone.om.KeyManager;
import org.apache.hadoop.ozone.om.OzoneAclUtils;
import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.PrefixManager;
import org.apache.hadoop.ozone.om.VolumeManager;
import org.apache.hadoop.ozone.om.exceptions.OMException;
Expand All @@ -42,7 +42,7 @@
*/
@InterfaceAudience.LimitedPrivate({"HDFS", "Yarn", "Ranger", "Hive", "HBase"})
@InterfaceStability.Evolving
public class OzoneNativeAuthorizer implements IAccessAuthorizer {
public class OzoneNativeAuthorizer implements OzoneManagerAuthorizer {

private static final Logger LOG =
LoggerFactory.getLogger(OzoneNativeAuthorizer.class);
Expand Down Expand Up @@ -189,30 +189,18 @@ public boolean checkAccess(IOzoneObj ozObject, RequestContext context)
}
}

public void setVolumeManager(VolumeManager volumeManager) {
this.volumeManager = volumeManager;
}

public void setBucketManager(BucketManager bucketManager) {
this.bucketManager = bucketManager;
}

public void setKeyManager(KeyManager keyManager) {
this.keyManager = keyManager;
}

public void setPrefixManager(PrefixManager prefixManager) {
this.prefixManager = prefixManager;
}

@VisibleForTesting
void setOzoneAdmins(OzoneAdmins admins) {
setAdminCheck(admins::isAdmin);
}

@VisibleForTesting
void setOzoneReadOnlyAdmins(OzoneAdmins readOnlyAdmins) {
setReadOnlyAdminCheck(readOnlyAdmins::isAdmin);
@Override
public OzoneNativeAuthorizer configure(OzoneManager om, KeyManager km, PrefixManager pm) {
Objects.requireNonNull(om, "om == null");
volumeManager = om.getVolumeManager();
bucketManager = om.getBucketManager();
allowListAllVolumes = om::getAllowListAllVolumes;
setAdminCheck(om::isAdmin);
setReadOnlyAdminCheck(om::isReadOnlyAdmin);

keyManager = km;
prefixManager = pm;
return this;
}

public void setAdminCheck(Predicate<UserGroupInformation> check) {
Expand All @@ -223,10 +211,6 @@ public void setReadOnlyAdminCheck(Predicate<UserGroupInformation> check) {
readOnlyAdminCheck = Objects.requireNonNull(check, "read-only admin check");
}

public void setAllowListAllVolumes(BooleanSupplier allowListAllVolumes) {
this.allowListAllVolumes = Objects.requireNonNull(allowListAllVolumes, "allowListAllVolumes");
}

public boolean getAllowListAllVolumes() {
return allowListAllVolumes.getAsBoolean();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import org.apache.hadoop.hdds.server.OzoneAdmins;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.security.UserGroupInformation;
Expand Down Expand Up @@ -57,6 +59,22 @@ public void testCreateVolume() throws Exception {
}
}

static Predicate<UserGroupInformation> newAdminUserPredicate(List<String> adminUsernames) {
return new OzoneAdmins(adminUsernames, null)::isAdmin;
}

static Predicate<UserGroupInformation> newAdminUserPredicate(String adminUsername) {
return newAdminUserPredicate(Collections.singletonList(adminUsername));
}

static Predicate<UserGroupInformation> newAdminGroupPredicate(List<String> adminGroupNames) {
return new OzoneAdmins(null, adminGroupNames)::isAdmin;
}

static Predicate<UserGroupInformation> newAdminGroupPredicate(String adminGroupName) {
return newAdminGroupPredicate(Collections.singletonList(adminGroupName));
}

@Test
public void testBucketOperation() throws OMException {
UserGroupInformation.createUserForTesting("testuser",
Expand All @@ -65,8 +83,7 @@ public void testBucketOperation() throws OMException {
OzoneObj obj = getTestBucketobj("testbucket");
RequestContext context = getUserRequestContext("testuser",
IAccessAuthorizer.ACLType.LIST);
nativeAuthorizer.setOzoneReadOnlyAdmins(new OzoneAdmins(
Collections.singletonList("testuser"), null));
nativeAuthorizer.setReadOnlyAdminCheck(newAdminUserPredicate("testuser"));
assertTrue(nativeAuthorizer.checkAccess(obj, context),
"matching read only admins are allowed to preform" +
"read operations");
Expand All @@ -91,8 +108,7 @@ public void testBucketOperation() throws OMException {
assertThrows(NullPointerException.class,
() -> nativeAuthorizer.checkAccess(obj, finalContext));

nativeAuthorizer.setOzoneReadOnlyAdmins(new OzoneAdmins(
null, Collections.singletonList("testgroup")));
nativeAuthorizer.setReadOnlyAdminCheck(newAdminGroupPredicate("testgroup"));
context = getUserRequestContext("testuser",
IAccessAuthorizer.ACLType.READ_ACL);
assertTrue(nativeAuthorizer.checkAccess(obj, context),
Expand Down Expand Up @@ -120,37 +136,34 @@ public void testListAllVolume() throws Exception {

private void testAdminOperations(OzoneObj obj, RequestContext context)
throws OMException {
nativeAuthorizer.setOzoneAdmins(new OzoneAdmins(Collections.emptyList()));
nativeAuthorizer.setAdminCheck(newAdminUserPredicate(Collections.emptyList()));
assertFalse(nativeAuthorizer.checkAccess(obj, context), "empty" +
" admin list disallow anyone to perform " +
"admin operations");

nativeAuthorizer.setOzoneAdmins(new OzoneAdmins(
Collections.singletonList(OZONE_ADMINISTRATORS_WILDCARD)));
nativeAuthorizer.setAdminCheck(newAdminUserPredicate(OZONE_ADMINISTRATORS_WILDCARD));
assertTrue(nativeAuthorizer.checkAccess(obj, context),
"wildcard admin allows everyone to perform admin" +
" operations");

nativeAuthorizer.setOzoneAdmins(new OzoneAdmins(
Collections.singletonList("testuser")));
nativeAuthorizer.setAdminCheck(newAdminUserPredicate("testuser"));
assertTrue(nativeAuthorizer.checkAccess(obj, context),
"matching admins are allowed to perform admin " +
"operations");

nativeAuthorizer.setOzoneAdmins(new OzoneAdmins(
asList(new String[]{"testuser2", "testuser"})));
nativeAuthorizer.setAdminCheck(newAdminUserPredicate(
asList("testuser2", "testuser")));
assertTrue(nativeAuthorizer.checkAccess(obj, context),
"matching admins are allowed to perform admin " +
"operations");

nativeAuthorizer.setOzoneAdmins(new OzoneAdmins(
asList(new String[]{"testuser2", "testuser3"})));
nativeAuthorizer.setAdminCheck(newAdminUserPredicate(
asList("testuser2", "testuser3")));
assertFalse(nativeAuthorizer.checkAccess(obj, context),
"mismatching admins are not allowed perform " +
"admin operations");

nativeAuthorizer.setOzoneReadOnlyAdmins(new OzoneAdmins(
Collections.singletonList("testuser"), null));
nativeAuthorizer.setReadOnlyAdminCheck(newAdminUserPredicate("testuser"));
if (context.getAclRights() == IAccessAuthorizer.ACLType.LIST) {
assertTrue(nativeAuthorizer.checkAccess(obj, context),
"matching read only user are allowed to preform" +
Expand All @@ -161,29 +174,25 @@ private void testAdminOperations(OzoneObj obj, RequestContext context)
"read operations");
}

nativeAuthorizer.setOzoneReadOnlyAdmins(new OzoneAdmins(
Collections.singletonList("testuser1"), null));
nativeAuthorizer.setReadOnlyAdminCheck(newAdminUserPredicate("testuser1"));
assertFalse(nativeAuthorizer.checkAccess(obj, context),
"mismatching read only user are allowed to preform" +
"read operations");
}

private void testGroupAdminOperations(OzoneObj obj, RequestContext context)
throws OMException {
nativeAuthorizer.setOzoneAdmins(
new OzoneAdmins(null, asList("testgroup", "anothergroup")));
nativeAuthorizer.setAdminCheck(newAdminGroupPredicate(asList("testgroup", "anothergroup")));
assertTrue(nativeAuthorizer.checkAccess(obj, context), "Users " +
"from matching admin groups " +
"are allowed to perform admin operations");

nativeAuthorizer.setOzoneAdmins(
new OzoneAdmins(null, asList("wronggroup")));
nativeAuthorizer.setAdminCheck(newAdminGroupPredicate("wronggroup"));
assertFalse(nativeAuthorizer.checkAccess(obj, context), "Users" +
" from mismatching admin groups " +
"are allowed to perform admin operations");

nativeAuthorizer.setOzoneReadOnlyAdmins(new OzoneAdmins(
null, Collections.singletonList("testgroup")));
nativeAuthorizer.setReadOnlyAdminCheck(newAdminGroupPredicate("testgroup"));
if (context.getAclRights() == IAccessAuthorizer.ACLType.LIST) {
assertTrue(nativeAuthorizer.checkAccess(obj, context),
"matching read only groups are allowed to preform" +
Expand All @@ -194,8 +203,7 @@ private void testGroupAdminOperations(OzoneObj obj, RequestContext context)
"preform read operations");
}

nativeAuthorizer.setOzoneReadOnlyAdmins(new OzoneAdmins(
null, Collections.singletonList("testgroup1")));
nativeAuthorizer.setReadOnlyAdminCheck(newAdminGroupPredicate("testgroup1"));
assertFalse(nativeAuthorizer.checkAccess(obj, context),
"mismatching read only groups are allowed to preform" +
"read operations");
Expand Down