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 @@ -21,6 +21,7 @@
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -78,6 +79,7 @@
import org.apache.hadoop.fs.azurebfs.extensions.ExtensionHelper;
import org.apache.hadoop.fs.azurebfs.oauth2.AccessTokenProvider;
import org.apache.hadoop.fs.azurebfs.oauth2.IdentityTransformer;
import org.apache.hadoop.fs.azurebfs.oauth2.IdentityTransformerInterface;
import org.apache.hadoop.fs.azurebfs.services.AbfsAclHelper;
import org.apache.hadoop.fs.azurebfs.services.AbfsClient;
import org.apache.hadoop.fs.azurebfs.services.AbfsHttpOperation;
Expand Down Expand Up @@ -115,6 +117,7 @@
import static org.apache.hadoop.fs.azurebfs.constants.AbfsHttpConstants.SINGLE_WHITE_SPACE;
import static org.apache.hadoop.fs.azurebfs.constants.AbfsHttpConstants.TOKEN_VERSION;
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.AZURE_ABFS_ENDPOINT;
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_IDENTITY_TRANSFORM_CLASS;

/**
* Provides the bridging logic between Hadoop's abstract filesystem and Azure Storage.
Expand All @@ -137,7 +140,7 @@ public class AzureBlobFileSystemStore implements Closeable {
private Trilean isNamespaceEnabled;
private final AuthType authType;
private final UserGroupInformation userGroupInformation;
private final IdentityTransformer identityTransformer;
private final IdentityTransformerInterface identityTransformer;
private final AbfsPerfTracker abfsPerfTracker;

public AzureBlobFileSystemStore(URI uri, boolean isSecureScheme, Configuration configuration)
Expand Down Expand Up @@ -180,7 +183,15 @@ public AzureBlobFileSystemStore(URI uri, boolean isSecureScheme, Configuration c
boolean useHttps = (usingOauth || abfsConfiguration.isHttpsAlwaysUsed()) ? true : isSecureScheme;
this.abfsPerfTracker = new AbfsPerfTracker(fileSystemName, accountName, this.abfsConfiguration);
initializeClient(uri, fileSystemName, accountName, useHttps);
this.identityTransformer = new IdentityTransformer(abfsConfiguration.getRawConfiguration());
final Class<? extends IdentityTransformerInterface> identityTransformerClass =
configuration.getClass(FS_AZURE_IDENTITY_TRANSFORM_CLASS, IdentityTransformer.class,
IdentityTransformerInterface.class);
try {
this.identityTransformer =
identityTransformerClass.getConstructor(Configuration.class).newInstance(configuration);
} catch (IllegalAccessException | InstantiationException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException e) {
throw new IOException(e);
}
LOG.trace("IdentityTransformer init complete");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public final class AbfsHttpConstants {
public static final String SEMICOLON = ";";
public static final String AT = "@";
public static final String HTTP_HEADER_PREFIX = "x-ms-";
public static final String HASH = "#";

public static final String PLUS_ENCODE = "%20";
public static final String FORWARD_SLASH_ENCODE = "%2F";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,12 @@ public static String accountProperty(String property, String account) {
/** For performance, AbfsInputStream/AbfsOutputStream re-use SAS tokens until the expiry is within this number of seconds. **/
public static final String FS_AZURE_SAS_TOKEN_RENEW_PERIOD_FOR_STREAMS = "fs.azure.sas.token.renew.period.for.streams";

/** Key to enable custom identity transformation. */
public static final String FS_AZURE_IDENTITY_TRANSFORM_CLASS = "fs.azure.identity.transformer.class";
/** Key for Local User to Service Principal file location. */
public static final String FS_AZURE_LOCAL_USER_SP_MAPPING_FILE_PATH = "fs.azure.identity.transformer.local.service.principal.mapping.file.path";
/** Key for Local Group to Service Group file location. */
public static final String FS_AZURE_LOCAL_GROUP_SG_MAPPING_FILE_PATH = "fs.azure.identity.transformer.local.service.group.mapping.file.path";

private ConfigurationKeys() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
/**
* Perform transformation for Azure Active Directory identities used in owner, group and acls.
*/
public class IdentityTransformer {
public class IdentityTransformer implements IdentityTransformerInterface {
private static final Logger LOG = LoggerFactory.getLogger(IdentityTransformer.class);

private boolean isSecure;
Expand Down Expand Up @@ -100,7 +100,8 @@ public IdentityTransformer(Configuration configuration) throws IOException {
* @param localIdentity the local user or group, should be parsed from UserGroupInformation.
* @return owner or group after transformation.
* */
public String transformIdentityForGetRequest(String originalIdentity, boolean isUserName, String localIdentity) {
public String transformIdentityForGetRequest(String originalIdentity, boolean isUserName, String localIdentity)
throws IOException {
if (originalIdentity == null) {
originalIdentity = localIdentity;
// localIdentity might be a full name, so continue the transformation.
Expand Down Expand Up @@ -198,7 +199,7 @@ public void transformAclEntriesForSetRequest(final List<AclEntry> aclEntries) {
if (isInSubstitutionList(name)) {
transformedName = servicePrincipalId;
} else if (aclEntry.getType().equals(AclEntryType.USER) // case 2: when the owner is a short name
&& shouldUseFullyQualifiedUserName(name)) { // of the user principal name (UPN).
&& shouldUseFullyQualifiedUserName(name)) { // of the user principal name (UPN).
// Notice: for group type ACL entry, if name is shortName.
// It won't be converted to Full Name. This is
// to make the behavior consistent with HDI.
Expand Down Expand Up @@ -242,7 +243,8 @@ && shouldUseFullyQualifiedUserName(name)) { // of the user principal
* @param localUser local user name
* @param localGroup local primary group
* */
public void transformAclEntriesForGetRequest(final List<AclEntry> aclEntries, String localUser, String localGroup) {
public void transformAclEntriesForGetRequest(final List<AclEntry> aclEntries, String localUser, String localGroup)
throws IOException {
if (skipUserIdentityReplacement) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* 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.oauth2;

import java.io.IOException;
import java.util.List;

import org.apache.hadoop.fs.permission.AclEntry;

/**
* {@code IdentityTransformerInterface} defines the set of translation
* operations that any identity transformer implementation must provide.
*/
public interface IdentityTransformerInterface {

/**
* Perform identity transformation for the Get request.
* @param originalIdentity the original user or group in the get request.
* @param isUserName indicate whether the input originalIdentity is an owner name or owning group name.
* @param localIdentity the local user or group, should be parsed from UserGroupInformation.
* @return owner or group after transformation.
*/
String transformIdentityForGetRequest(String originalIdentity, boolean isUserName, String localIdentity)
throws IOException;

/**
* Perform Identity transformation when setting owner on a path.
* @param userOrGroup the user or group to be set as owner.
* @return user or group after transformation.
*/
String transformUserOrGroupForSetRequest(String userOrGroup);

/**
* Perform Identity transformation when calling setAcl(),removeAclEntries() and modifyAclEntries().
* @param aclEntries list of AclEntry.
*/
void transformAclEntriesForSetRequest(final List<AclEntry> aclEntries);

/**
* Perform Identity transformation when calling GetAclStatus().
* @param aclEntries list of AclEntry.
* @param localUser local user name.
* @param localGroup local primary group.
*/
void transformAclEntriesForGetRequest(final List<AclEntry> aclEntries, String localUser, String localGroup)
throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* 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.oauth2;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.azurebfs.utils.IdentityHandler;
import org.apache.hadoop.fs.azurebfs.utils.TextFileBasedIdentityHandler;

import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_LOCAL_USER_SP_MAPPING_FILE_PATH;
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.FS_AZURE_LOCAL_GROUP_SG_MAPPING_FILE_PATH;


/**
* A subclass of {@link IdentityTransformer} that translates the AAD to Local
* identity using {@link IdentityHandler}.
*
* {@link TextFileBasedIdentityHandler} is a {@link IdentityHandler} implements
* translation operation which returns identity mapped to AAD identity.
*/
public class LocalIdentityTransformer extends IdentityTransformer {

private static final Logger LOG = LoggerFactory.getLogger(LocalIdentityTransformer.class);

private IdentityHandler localToAadIdentityLookup;

public LocalIdentityTransformer(Configuration configuration) throws IOException {
super(configuration);
this.localToAadIdentityLookup =
new TextFileBasedIdentityHandler(configuration.get(FS_AZURE_LOCAL_USER_SP_MAPPING_FILE_PATH),
configuration.get(FS_AZURE_LOCAL_GROUP_SG_MAPPING_FILE_PATH));
}

/**
* Perform identity transformation for the Get request results.
* @param originalIdentity the original user or group in the get request results: FileStatus, AclStatus.
* @param isUserName indicate whether the input originalIdentity is an owner name or owning group name.
* @param localIdentity the local user or group, should be parsed from UserGroupInformation.
* @return local identity.
*/
@Override
public String transformIdentityForGetRequest(String originalIdentity, boolean isUserName, String localIdentity)
throws IOException {
String localIdentityForOrig = isUserName ? localToAadIdentityLookup.lookupForLocalUserIdentity(originalIdentity)
: localToAadIdentityLookup.lookupForLocalGroupIdentity(originalIdentity);

if (localIdentityForOrig == null || localIdentityForOrig.isEmpty()) {
return super.transformIdentityForGetRequest(originalIdentity, isUserName, localIdentity);
}

return localIdentityForOrig;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* 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.utils;

import java.io.IOException;


/**
* {@code IdentityHandler} defines the set of methods to support various
* identity lookup services.
*/
public interface IdentityHandler {

/**
* Perform lookup from Service Principal's Object ID to Username.
* @param originalIdentity AAD object ID.
* @return User name, if no name found returns empty string.
* */
String lookupForLocalUserIdentity(String originalIdentity) throws IOException;

/**
* Perform lookup from Security Group's Object ID to Security Group name.
* @param originalIdentity AAD object ID.
* @return Security group name, if no name found returns empty string.
* */
String lookupForLocalGroupIdentity(String originalIdentity) throws IOException;
}
Loading