blob: 1f5072d58eda3c9b9ae39a5799228f4cbae98fe1 [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.hadoop.fs.azure;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.fs.Path;
/**
* A mock wasb authorizer implementation.
*/
public class MockWasbAuthorizerImpl implements WasbAuthorizerInterface {
private Map<AuthorizationComponent, Boolean> authRules;
private CachingAuthorizer<CachedAuthorizerEntry, Boolean> cache;
// The full qualified URL to the root directory
private String qualifiedPrefixUrl;
public MockWasbAuthorizerImpl(NativeAzureFileSystem fs) {
qualifiedPrefixUrl = new Path("/").makeQualified(fs.getUri(),
fs.getWorkingDirectory())
.toString().replaceAll("/$", "");
cache = new CachingAuthorizer<>(TimeUnit.MINUTES.convert(5L, TimeUnit.MINUTES), "AUTHORIZATION");
}
@Override
public void init(Configuration conf) {
cache.init(conf);
authRules = new HashMap<>();
}
public void addAuthRuleForOwner(String wasbAbsolutePath,
String accessType, boolean access) {
addAuthRule(wasbAbsolutePath, accessType, "owner", access);
}
public void addAuthRule(String wasbAbsolutePath,
String accessType, String user, boolean access) {
wasbAbsolutePath = qualifiedPrefixUrl + wasbAbsolutePath;
AuthorizationComponent component = wasbAbsolutePath.endsWith("*")
? new AuthorizationComponent("^" + wasbAbsolutePath.replace("*", ".*"),
accessType, user)
: new AuthorizationComponent(wasbAbsolutePath, accessType, user);
this.authRules.put(component, access);
}
@Override
public boolean authorize(String wasbAbsolutePath,
String accessType,
String owner)
throws WasbAuthorizationException {
if (wasbAbsolutePath.endsWith(
NativeAzureFileSystem.FolderRenamePending.SUFFIX)) {
return true;
}
CachedAuthorizerEntry cacheKey = new CachedAuthorizerEntry(wasbAbsolutePath, accessType, owner);
Boolean cacheresult = cache.get(cacheKey);
if (cacheresult != null) {
return cacheresult;
}
boolean authorizeresult = authorizeInternal(wasbAbsolutePath, accessType, owner);
cache.put(cacheKey, authorizeresult);
return authorizeresult;
}
private boolean authorizeInternal(String wasbAbsolutePath, String accessType, String owner)
throws WasbAuthorizationException {
String currentUserShortName = "";
try {
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
currentUserShortName = ugi.getShortUserName();
} catch (Exception e) {
//no op
}
// In case of root("/"), owner match does not happen
// because owner is returned as empty string.
// we try to force owner match just for purpose of tests
// to make sure all operations work seemlessly with owner.
if (StringUtils.equalsIgnoreCase(wasbAbsolutePath, qualifiedPrefixUrl + "/")) {
owner = currentUserShortName;
}
AuthorizationComponent component = new AuthorizationComponent(wasbAbsolutePath,
accessType, currentUserShortName);
return processRules(authRules, component, owner);
}
private boolean processRules(Map<AuthorizationComponent, Boolean> authRules,
AuthorizationComponent component, String owner) {
// Direct match of rules and access request
if (authRules.containsKey(component)) {
return authRules.get(component);
} else {
// Regex-pattern match if we don't have a straight match for path
// Current user match if we don't have a owner match
for (Map.Entry<AuthorizationComponent, Boolean> entry : authRules.entrySet()) {
AuthorizationComponent key = entry.getKey();
String keyPath = key.getWasbAbsolutePath();
String keyAccess = key.getAccessType();
String keyUser = key.getUser();
boolean foundMatchingOwnerRule = keyPath.equals(component.getWasbAbsolutePath())
&& keyAccess.equals(component.getAccessType())
&& keyUser.equalsIgnoreCase("owner")
&& owner.equals(component.getUser());
boolean foundMatchingPatternRule = keyPath.endsWith("*")
&& Pattern.matches(keyPath, component.getWasbAbsolutePath())
&& keyAccess.equals(component.getAccessType())
&& keyUser.equalsIgnoreCase(component.getUser());
boolean foundMatchingPatternOwnerRule = keyPath.endsWith("*")
&& Pattern.matches(keyPath, component.getWasbAbsolutePath())
&& keyAccess.equals(component.getAccessType())
&& keyUser.equalsIgnoreCase("owner")
&& owner.equals(component.getUser());
if (foundMatchingOwnerRule
|| foundMatchingPatternRule
|| foundMatchingPatternOwnerRule) {
return entry.getValue();
}
}
return false;
}
}
public void deleteAllAuthRules() {
authRules.clear();
cache.clear();
}
private static class AuthorizationComponent {
private final String wasbAbsolutePath;
private final String accessType;
private final String user;
AuthorizationComponent(String wasbAbsolutePath,
String accessType, String user) {
this.wasbAbsolutePath = wasbAbsolutePath;
this.accessType = accessType;
this.user = user;
}
@Override
public int hashCode() {
return this.wasbAbsolutePath.hashCode() ^ this.accessType.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null
|| !(obj instanceof AuthorizationComponent)) {
return false;
}
return ((AuthorizationComponent) obj).
getWasbAbsolutePath().equals(this.wasbAbsolutePath)
&& ((AuthorizationComponent) obj).
getAccessType().equals(this.accessType)
&& ((AuthorizationComponent) obj).
getUser().equals(this.user);
}
public String getWasbAbsolutePath() {
return this.wasbAbsolutePath;
}
public String getAccessType() {
return accessType;
}
public String getUser() {
return user;
}
}
}