|
@@ -0,0 +1,301 @@
|
|
|
+/**
|
|
|
+ * 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.fs.azurebfs;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.util.List;
|
|
|
+import java.util.UUID;
|
|
|
+
|
|
|
+import com.google.common.collect.Lists;
|
|
|
+import org.apache.hadoop.fs.azurebfs.oauth2.IdentityTransformer;
|
|
|
+import org.apache.hadoop.fs.permission.AclEntry;
|
|
|
+import org.junit.Test;
|
|
|
+
|
|
|
+import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.security.UserGroupInformation;
|
|
|
+
|
|
|
+import static org.apache.hadoop.fs.azurebfs.constants.AbfsHttpConstants.SUPER_USER;
|
|
|
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_FILE_OWNER_DOMAINNAME;
|
|
|
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME;
|
|
|
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_OVERRIDE_OWNER_SP;
|
|
|
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_OVERRIDE_OWNER_SP_LIST;
|
|
|
+import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_SKIP_SUPER_USER_REPLACEMENT;
|
|
|
+import static org.apache.hadoop.fs.azurebfs.utils.AclTestHelpers.aclEntry;
|
|
|
+import static org.apache.hadoop.fs.permission.AclEntryScope.ACCESS;
|
|
|
+import static org.apache.hadoop.fs.permission.AclEntryScope.DEFAULT;
|
|
|
+import static org.apache.hadoop.fs.permission.AclEntryType.GROUP;
|
|
|
+import static org.apache.hadoop.fs.permission.AclEntryType.MASK;
|
|
|
+import static org.apache.hadoop.fs.permission.AclEntryType.OTHER;
|
|
|
+import static org.apache.hadoop.fs.permission.AclEntryType.USER;
|
|
|
+import static org.apache.hadoop.fs.permission.FsAction.ALL;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Test IdentityTransformer.
|
|
|
+ */
|
|
|
+//@RunWith(Parameterized.class)
|
|
|
+public class ITestAbfsIdentityTransformer extends AbstractAbfsScaleTest{
|
|
|
+ private final UserGroupInformation userGroupInfo;
|
|
|
+ private final String localUser;
|
|
|
+ private final String localGroup;
|
|
|
+ private static final String DAEMON = "daemon";
|
|
|
+ private static final String ASTERISK = "*";
|
|
|
+ private static final String SHORT_NAME = "abc";
|
|
|
+ private static final String DOMAIN = "domain.com";
|
|
|
+ private static final String FULLY_QUALIFIED_NAME = "abc@domain.com";
|
|
|
+ private static final String SERVICE_PRINCIPAL_ID = UUID.randomUUID().toString();
|
|
|
+
|
|
|
+ public ITestAbfsIdentityTransformer() throws Exception {
|
|
|
+ super();
|
|
|
+ userGroupInfo = UserGroupInformation.getCurrentUser();
|
|
|
+ localUser = userGroupInfo.getShortUserName();
|
|
|
+ localGroup = userGroupInfo.getPrimaryGroupName();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testDaemonServiceSettingIdentity() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // Default config
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ assertEquals("Identity should not change for default config",
|
|
|
+ DAEMON, identityTransformer.transformUserOrGroupForSetRequest(DAEMON));
|
|
|
+
|
|
|
+ // Add service principal id
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, SERVICE_PRINCIPAL_ID);
|
|
|
+
|
|
|
+ // case 1: substitution list doesn't contain daemon
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, "a,b,c,d");
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("Identity should not change when substitution list doesn't contain daemon",
|
|
|
+ DAEMON, identityTransformer.transformUserOrGroupForSetRequest(DAEMON));
|
|
|
+
|
|
|
+ // case 2: substitution list contains daemon name
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, DAEMON + ",a,b,c,d");
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("Identity should be replaced to servicePrincipalId",
|
|
|
+ SERVICE_PRINCIPAL_ID, identityTransformer.transformUserOrGroupForSetRequest(DAEMON));
|
|
|
+
|
|
|
+ // case 3: substitution list is *
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, ASTERISK);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("Identity should be replaced to servicePrincipalId",
|
|
|
+ SERVICE_PRINCIPAL_ID, identityTransformer.transformUserOrGroupForSetRequest(DAEMON));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testFullyQualifiedNameSettingIdentity() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ // Default config
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ assertEquals("short name should not be converted to full name by default",
|
|
|
+ SHORT_NAME, identityTransformer.transformUserOrGroupForSetRequest(SHORT_NAME));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ // Add config to get fully qualified username
|
|
|
+ config.setBoolean(FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME, true);
|
|
|
+ config.set(FS_AZURE_FILE_OWNER_DOMAINNAME, DOMAIN);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("short name should be converted to full name",
|
|
|
+ FULLY_QUALIFIED_NAME, identityTransformer.transformUserOrGroupForSetRequest(SHORT_NAME));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testNoOpForSettingOidAsIdentity() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ config.setBoolean(FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME, true);
|
|
|
+ config.set(FS_AZURE_FILE_OWNER_DOMAINNAME, DOMAIN);
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, UUID.randomUUID().toString());
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, "a,b,c,d");
|
|
|
+
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ final String principalId = UUID.randomUUID().toString();
|
|
|
+ assertEquals("Identity should not be changed when owner is already a principal id ",
|
|
|
+ principalId, identityTransformer.transformUserOrGroupForSetRequest(principalId));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testNoOpWhenSettingSuperUserAsdentity() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ config.setBoolean(FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME, true);
|
|
|
+ config.set(FS_AZURE_FILE_OWNER_DOMAINNAME, DOMAIN);
|
|
|
+ // Default config
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ assertEquals("Identity should not be changed because it is not in substitution list",
|
|
|
+ SUPER_USER, identityTransformer.transformUserOrGroupForSetRequest(SUPER_USER));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testIdentityReplacementForSuperUserGetRequest() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ // with default config, identityTransformer should do $superUser replacement
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ assertEquals("$superuser should be replaced with local user by default",
|
|
|
+ localUser, identityTransformer.transformIdentityForGetRequest(SUPER_USER, localUser));
|
|
|
+
|
|
|
+ // Disable $supeuser replacement
|
|
|
+ config.setBoolean(FS_AZURE_SKIP_SUPER_USER_REPLACEMENT, true);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("$superuser should not be replaced",
|
|
|
+ SUPER_USER, identityTransformer.transformIdentityForGetRequest(SUPER_USER, localUser));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testIdentityReplacementForDaemonServiceGetRequest() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ // Default config
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ assertEquals("By default servicePrincipalId should not be converted for GetFileStatus(), listFileStatus(), getAcl()",
|
|
|
+ SERVICE_PRINCIPAL_ID, identityTransformer.transformIdentityForGetRequest(SERVICE_PRINCIPAL_ID, localUser));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // 1. substitution list doesn't contain currentUser
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, "a,b,c,d");
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("servicePrincipalId should not be replaced if local daemon user is not in substitution list",
|
|
|
+ SERVICE_PRINCIPAL_ID, identityTransformer.transformIdentityForGetRequest(SERVICE_PRINCIPAL_ID, localUser));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // 2. substitution list contains currentUser(daemon name) but the service principal id in config doesn't match
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, localUser + ",a,b,c,d");
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, UUID.randomUUID().toString());
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("servicePrincipalId should not be replaced if it is not equal to the SPN set in config",
|
|
|
+ SERVICE_PRINCIPAL_ID, identityTransformer.transformIdentityForGetRequest(SERVICE_PRINCIPAL_ID, localUser));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // 3. substitution list contains currentUser(daemon name) and the service principal id in config matches
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, localUser + ",a,b,c,d");
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, SERVICE_PRINCIPAL_ID);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("servicePrincipalId should be transformed to local use",
|
|
|
+ localUser, identityTransformer.transformIdentityForGetRequest(SERVICE_PRINCIPAL_ID, localUser));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // 4. substitution is "*" but the service principal id in config doesn't match the input
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, ASTERISK);
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, UUID.randomUUID().toString());
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("servicePrincipalId should not be replaced if it is not equal to the SPN set in config",
|
|
|
+ SERVICE_PRINCIPAL_ID, identityTransformer.transformIdentityForGetRequest(SERVICE_PRINCIPAL_ID, localUser));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // 5. substitution is "*" and the service principal id in config match the input
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, ASTERISK);
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, SERVICE_PRINCIPAL_ID);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("servicePrincipalId should be transformed to local user",
|
|
|
+ localUser, identityTransformer.transformIdentityForGetRequest(SERVICE_PRINCIPAL_ID, localUser));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void testIdentityReplacementForKinitUserGetRequest() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ // Default config
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ assertEquals("full name should not be transformed if shortname is not enabled",
|
|
|
+ FULLY_QUALIFIED_NAME, identityTransformer.transformIdentityForGetRequest(FULLY_QUALIFIED_NAME, localUser));
|
|
|
+
|
|
|
+ // add config to get short name
|
|
|
+ config.setBoolean(FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME, true);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+ assertEquals("should convert the full name to shortname ",
|
|
|
+ SHORT_NAME, identityTransformer.transformIdentityForGetRequest(FULLY_QUALIFIED_NAME, localUser));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ public void transformAclEntriesForSetRequest() throws IOException {
|
|
|
+ Configuration config = this.getRawConfiguration();
|
|
|
+ resetIdentityConfig(config);
|
|
|
+
|
|
|
+ List<AclEntry> aclEntriesToBeTransformed = Lists.newArrayList(
|
|
|
+ aclEntry(ACCESS, USER, DAEMON, ALL),
|
|
|
+ aclEntry(ACCESS, USER, FULLY_QUALIFIED_NAME,ALL),
|
|
|
+ aclEntry(DEFAULT, USER, SUPER_USER, ALL),
|
|
|
+ aclEntry(DEFAULT, USER, SERVICE_PRINCIPAL_ID, ALL),
|
|
|
+ aclEntry(DEFAULT, USER, SHORT_NAME, ALL),
|
|
|
+ aclEntry(DEFAULT, GROUP, DAEMON, ALL),
|
|
|
+ aclEntry(DEFAULT, GROUP, SHORT_NAME, ALL), // Notice: for group type ACL entry, if name is shortName,
|
|
|
+ aclEntry(DEFAULT, OTHER, ALL), // It won't be converted to Full Name. This is
|
|
|
+ aclEntry(DEFAULT, MASK, ALL) // to make the behavior consistent with HDI.
|
|
|
+ );
|
|
|
+
|
|
|
+ // Default config should not change the identities
|
|
|
+ IdentityTransformer identityTransformer = getTransformerWithDefaultIdentityConfig(config);
|
|
|
+ checkAclEntriesList(aclEntriesToBeTransformed, identityTransformer.transformAclEntriesForSetRequest(aclEntriesToBeTransformed));
|
|
|
+
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ // With config
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP_LIST, DAEMON + ",a,b,c,d");
|
|
|
+ config.setBoolean(FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME, true);
|
|
|
+ config.set(FS_AZURE_FILE_OWNER_DOMAINNAME, DOMAIN);
|
|
|
+ config.set(FS_AZURE_OVERRIDE_OWNER_SP, SERVICE_PRINCIPAL_ID);
|
|
|
+ identityTransformer = getTransformerWithCustomizedIdentityConfig(config);
|
|
|
+
|
|
|
+ // expected acl entries
|
|
|
+ List<AclEntry> expectedAclEntries = Lists.newArrayList(
|
|
|
+ aclEntry(ACCESS, USER, SERVICE_PRINCIPAL_ID, ALL),
|
|
|
+ aclEntry(ACCESS, USER, FULLY_QUALIFIED_NAME, ALL),
|
|
|
+ aclEntry(DEFAULT, USER, SUPER_USER, ALL),
|
|
|
+ aclEntry(DEFAULT, USER, SERVICE_PRINCIPAL_ID, ALL),
|
|
|
+ aclEntry(DEFAULT, USER, FULLY_QUALIFIED_NAME, ALL),
|
|
|
+ aclEntry(DEFAULT, GROUP, SERVICE_PRINCIPAL_ID, ALL),
|
|
|
+ aclEntry(DEFAULT, GROUP, SHORT_NAME, ALL),
|
|
|
+ aclEntry(DEFAULT, OTHER, ALL),
|
|
|
+ aclEntry(DEFAULT, MASK, ALL)
|
|
|
+ );
|
|
|
+
|
|
|
+ checkAclEntriesList(identityTransformer.transformAclEntriesForSetRequest(aclEntriesToBeTransformed), expectedAclEntries);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void resetIdentityConfig(Configuration config) {
|
|
|
+ config.unset(FS_AZURE_FILE_OWNER_ENABLE_SHORTNAME);
|
|
|
+ config.unset(FS_AZURE_FILE_OWNER_DOMAINNAME);
|
|
|
+ config.unset(FS_AZURE_OVERRIDE_OWNER_SP);
|
|
|
+ config.unset(FS_AZURE_OVERRIDE_OWNER_SP_LIST);
|
|
|
+ config.unset(FS_AZURE_SKIP_SUPER_USER_REPLACEMENT);
|
|
|
+ }
|
|
|
+
|
|
|
+ private IdentityTransformer getTransformerWithDefaultIdentityConfig(Configuration config) throws IOException {
|
|
|
+ resetIdentityConfig(config);
|
|
|
+ return new IdentityTransformer(config);
|
|
|
+ }
|
|
|
+
|
|
|
+ private IdentityTransformer getTransformerWithCustomizedIdentityConfig(Configuration config) throws IOException {
|
|
|
+ return new IdentityTransformer(config);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void checkAclEntriesList(List<AclEntry> aclEntries, List<AclEntry> expected) {
|
|
|
+ assertTrue("list size not equals", aclEntries.size() == expected.size());
|
|
|
+ for (int i = 0; i < aclEntries.size(); i++) {
|
|
|
+ assertEquals("Identity doesn't match", expected.get(i).getName(), aclEntries.get(i).getName());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|