blob: 1b2da26b5d058c86fb6d9be6cef30d9242419c6d [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.impala.catalog;
import org.apache.impala.authorization.AuthorizationPolicy;
import org.apache.impala.thrift.TCatalogObject;
import org.apache.impala.thrift.TCatalogObjectType;
import org.apache.impala.thrift.TPrincipalType;
import org.apache.impala.thrift.TPrivilege;
import org.apache.impala.thrift.TPrivilegeLevel;
import org.apache.impala.thrift.TPrivilegeScope;
import org.apache.log4j.Logger;
import com.google.common.base.Preconditions;
/**
* Represents a privilege that has been granted to a principal in an authorization policy.
* This class is thread safe.
*/
public class PrincipalPrivilege extends CatalogObjectImpl {
private static final Logger LOG = Logger.getLogger(AuthorizationPolicy.class);
private static final String AUTHORIZABLE_SEPARATOR = "->";
private static final String KV_SEPARATOR = "=";
private final TPrivilege privilege_;
private PrincipalPrivilege(TPrivilege privilege) {
privilege_ = Preconditions.checkNotNull(privilege);
}
public TPrivilege toThrift() { return privilege_; }
public static PrincipalPrivilege fromThrift(TPrivilege privilege) {
return new PrincipalPrivilege(privilege);
}
/**
* Builds a privilege name for the given TPrivilege object. For simplicity, this name is
* generated in a format that can be sent to the Sentry client to perform authorization
* checks. The format is:
* [ServerName=value]->[DbName=value]->[TableName=value]->[ColumnName=value]->[Action Granted=value]->[Grant Option=value]
*/
public static String buildPrivilegeName(TPrivilege privilege) {
StringBuilder privilegeName = new StringBuilder();
Preconditions.checkNotNull(privilege);
TPrivilegeScope scope = privilege.getScope();
Preconditions.checkNotNull(scope);
switch (scope) {
case SERVER: {
privilegeName.append("server")
.append(KV_SEPARATOR)
.append(privilege.getServer_name().toLowerCase());
break;
}
case URI: {
privilegeName.append("server")
.append(KV_SEPARATOR)
.append(privilege.getServer_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
// (IMPALA-2695) URIs are case sensitive
privilegeName.append("uri")
.append(KV_SEPARATOR)
.append(privilege.getUri());
break;
}
case DATABASE: {
privilegeName.append("server")
.append(KV_SEPARATOR)
.append(privilege.getServer_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("db")
.append(KV_SEPARATOR)
.append(privilege.getDb_name().toLowerCase());
break;
}
case TABLE: {
privilegeName.append("server")
.append(KV_SEPARATOR)
.append(privilege.getServer_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("db")
.append(KV_SEPARATOR)
.append(privilege.getDb_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("table")
.append(KV_SEPARATOR)
.append(privilege.getTable_name().toLowerCase());
break;
}
case COLUMN: {
privilegeName.append("server")
.append(KV_SEPARATOR)
.append(privilege.getServer_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("db")
.append(KV_SEPARATOR)
.append(privilege.getDb_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("table")
.append(KV_SEPARATOR)
.append(privilege.getTable_name().toLowerCase());
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("column")
.append(KV_SEPARATOR)
.append(privilege.getColumn_name().toLowerCase());
break;
}
default: {
throw new UnsupportedOperationException(
"Unknown privilege scope: " + scope.toString());
}
}
// The ALL privilege is always implied and does not need to be included as part
// of the name.
if (privilege.getPrivilege_level() != TPrivilegeLevel.ALL) {
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("action")
.append(KV_SEPARATOR)
.append(privilege.getPrivilege_level().toString().toLowerCase());
}
privilegeName.append(AUTHORIZABLE_SEPARATOR);
privilegeName.append("grantoption")
.append(KV_SEPARATOR)
.append(privilege.isHas_grant_opt());
return privilegeName.toString();
}
/**
* Copies the given privilege and sets the has grant option.
*/
public static TPrivilege copyPrivilegeWithGrant(TPrivilege privilege,
boolean hasGrantOption) {
TPrivilege copy = privilege.deepCopy();
return copy.setHas_grant_opt(hasGrantOption);
}
@Override
public TCatalogObjectType getCatalogObjectType() {
return TCatalogObjectType.PRIVILEGE;
}
@Override
public String getName() { return buildPrivilegeName(privilege_); }
public int getPrincipalId() { return privilege_.getPrincipal_id(); }
public TPrincipalType getPrincipalType() { return privilege_.getPrincipal_type(); }
@Override
protected void setTCatalogObject(TCatalogObject catalogObject) {
catalogObject.setPrivilege(toThrift());
}
// The time this principal was created. Used to quickly check if the same privilege
// was dropped and re-created. Assumes a principal will not be created + dropped +
// created in less than 1ms. Returns -1 if create_time_ms was not set for the privilege.
public long getCreateTimeMs() {
return privilege_.isSetCreate_time_ms() ? privilege_.getCreate_time_ms() : -1L;
}
}