blob: fc49ef052ed5ab9e63a117a6a495b4e33b8e9d63 [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.ranger.admin.client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.security.AccessControlException;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.ranger.admin.client.datatype.RESTResponse;
import org.apache.ranger.audit.provider.MiscUtil;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.authorization.utils.StringUtil;
import org.apache.ranger.plugin.util.GrantRevokeRequest;
import org.apache.ranger.plugin.util.RangerRESTClient;
import org.apache.ranger.plugin.util.RangerRESTUtils;
import org.apache.ranger.plugin.util.RangerServiceNotFoundException;
import org.apache.ranger.plugin.util.ServicePolicies;
import org.apache.ranger.plugin.util.ServiceTags;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.PrivilegedAction;
import java.util.List;
public class RangerAdminRESTClient implements RangerAdminClient {
private static final Log LOG = LogFactory.getLog(RangerAdminRESTClient.class);
private String serviceName;
private String pluginId;
private String clusterName;
private RangerRESTClient restClient;
private RangerRESTUtils restUtils = new RangerRESTUtils();
private boolean forceNonKerberos = false;
public static <T> GenericType<List<T>> getGenericType(final T clazz) {
ParameterizedType parameterizedGenericType = new ParameterizedType() {
public Type[] getActualTypeArguments() {
return new Type[] { clazz.getClass() };
}
public Type getRawType() {
return List.class;
}
public Type getOwnerType() {
return List.class;
}
};
return new GenericType<List<T>>(parameterizedGenericType) {};
}
@Override
public void init(String serviceName, String appId, String propertyPrefix) {
this.serviceName = serviceName;
this.pluginId = restUtils.getPluginId(serviceName, appId);
String url = "";
String tmpUrl = RangerConfiguration.getInstance().get(propertyPrefix + ".policy.rest.url");
String sslConfigFileName = RangerConfiguration.getInstance().get(propertyPrefix + ".policy.rest.ssl.config.file");
clusterName = RangerConfiguration.getInstance().get(propertyPrefix + ".ambari.cluster.name", "");
int restClientConnTimeOutMs = RangerConfiguration.getInstance().getInt(propertyPrefix + ".policy.rest.client.connection.timeoutMs", 120 * 1000);
int restClientReadTimeOutMs = RangerConfiguration.getInstance().getInt(propertyPrefix + ".policy.rest.client.read.timeoutMs", 30 * 1000);
this.forceNonKerberos = RangerConfiguration.getInstance().getBoolean(propertyPrefix + ".forceNonKerberos", false);
if (!StringUtil.isEmpty(tmpUrl)) {
url = tmpUrl.trim();
}
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
init(url, sslConfigFileName, restClientConnTimeOutMs , restClientReadTimeOutMs);
}
@Override
public ServicePolicies getServicePoliciesIfUpdated(final long lastKnownVersion, final long lastActivationTimeInMillis) throws Exception {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + ")");
}
ServicePolicies ret = null;
UserGroupInformation user = MiscUtil.getUGILoginUser();
boolean isSecureMode = isKerberosEnabled(user);
ClientResponse response = null;
if (isSecureMode) {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking Service policy if updated as user : " + user);
}
PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() {
public ClientResponse run() {
WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SECURE_SERVICE_IF_UPDATED + serviceName)
.queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion))
.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId)
.queryParam(RangerRESTUtils.REST_PARAM_CLUSTER_NAME, clusterName);
return secureWebResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
}
};
response = user.doAs(action);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking Service policy if updated with old api call");
}
WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_POLICY_GET_FOR_SERVICE_IF_UPDATED + serviceName)
.queryParam(RangerRESTUtils.REST_PARAM_LAST_KNOWN_POLICY_VERSION, Long.toString(lastKnownVersion))
.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId)
.queryParam(RangerRESTUtils.REST_PARAM_CLUSTER_NAME, clusterName);
response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
}
if (response == null || response.getStatus() == HttpServletResponse.SC_NOT_MODIFIED) {
if (response == null) {
LOG.error("Error getting policies; Received NULL response!!. secureMode=" + isSecureMode + ", user=" + user + ", serviceName=" + serviceName);
} else {
RESTResponse resp = RESTResponse.fromClientResponse(response);
if (LOG.isDebugEnabled()) {
LOG.debug("No change in policies. secureMode=" + isSecureMode + ", user=" + user + ", response=" + resp + ", serviceName=" + serviceName);
}
}
ret = null;
} else if (response.getStatus() == HttpServletResponse.SC_OK) {
ret = response.getEntity(ServicePolicies.class);
} else if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND) {
LOG.error("Error getting policies; service not found. secureMode=" + isSecureMode + ", user=" + user
+ ", response=" + response.getStatus() + ", serviceName=" + serviceName
+ ", " + "lastKnownVersion=" + lastKnownVersion
+ ", " + "lastActivationTimeInMillis=" + lastActivationTimeInMillis);
String exceptionMsg = response.hasEntity() ? response.getEntity(String.class) : null;
RangerServiceNotFoundException.throwExceptionIfServiceNotFound(serviceName, exceptionMsg);
LOG.warn("Received 404 error code with body:[" + exceptionMsg + "], Ignoring");
} else {
RESTResponse resp = RESTResponse.fromClientResponse(response);
LOG.warn("Error getting policies. secureMode=" + isSecureMode + ", user=" + user + ", response=" + resp + ", serviceName=" + serviceName);
ret = null;
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminRESTClient.getServicePoliciesIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): " + ret);
}
return ret;
}
@Override
public void grantAccess(final GrantRevokeRequest request) throws Exception {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerAdminRESTClient.grantAccess(" + request + ")");
}
ClientResponse response = null;
UserGroupInformation user = MiscUtil.getUGILoginUser();
boolean isSecureMode = isKerberosEnabled(user);
if (isSecureMode) {
PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() {
public ClientResponse run() {
WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_SECURE_SERVICE_GRANT_ACCESS + serviceName)
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
return secureWebResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request));
}
};
if (LOG.isDebugEnabled()) {
LOG.debug("grantAccess as user " + user);
}
response = user.doAs(action);
} else {
WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_SERVICE_GRANT_ACCESS + serviceName)
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request));
}
if(response != null && response.getStatus() != HttpServletResponse.SC_OK) {
RESTResponse resp = RESTResponse.fromClientResponse(response);
LOG.error("grantAccess() failed: HTTP status=" + response.getStatus() + ", message=" + resp.getMessage() + ", isSecure=" + isSecureMode + (isSecureMode ? (", user=" + user) : ""));
if(response.getStatus()==HttpServletResponse.SC_UNAUTHORIZED) {
throw new AccessControlException();
}
throw new Exception("HTTP " + response.getStatus() + " Error: " + resp.getMessage());
} else if(response == null) {
throw new Exception("unknown error during grantAccess. serviceName=" + serviceName);
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminRESTClient.grantAccess(" + request + ")");
}
}
@Override
public void revokeAccess(final GrantRevokeRequest request) throws Exception {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerAdminRESTClient.revokeAccess(" + request + ")");
}
ClientResponse response = null;
UserGroupInformation user = MiscUtil.getUGILoginUser();
boolean isSecureMode = isKerberosEnabled(user);
if (isSecureMode) {
PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() {
public ClientResponse run() {
WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_SECURE_SERVICE_REVOKE_ACCESS + serviceName)
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
return secureWebResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request));
}
};
if (LOG.isDebugEnabled()) {
LOG.debug("revokeAccess as user " + user);
}
response = user.doAs(action);
} else {
WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_SERVICE_REVOKE_ACCESS + serviceName)
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
response = webResource.accept(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).type(RangerRESTUtils.REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request));
}
if(response != null && response.getStatus() != HttpServletResponse.SC_OK) {
RESTResponse resp = RESTResponse.fromClientResponse(response);
LOG.error("revokeAccess() failed: HTTP status=" + response.getStatus() + ", message=" + resp.getMessage() + ", isSecure=" + isSecureMode + (isSecureMode ? (", user=" + user) : ""));
if(response.getStatus() == HttpServletResponse.SC_UNAUTHORIZED) {
throw new AccessControlException();
}
throw new Exception("HTTP " + response.getStatus() + " Error: " + resp.getMessage());
} else if(response == null) {
throw new Exception("unknown error. revokeAccess(). serviceName=" + serviceName);
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminRESTClient.revokeAccess(" + request + ")");
}
}
private void init(String url, String sslConfigFileName, int restClientConnTimeOutMs , int restClientReadTimeOutMs ) {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerAdminRESTClient.init(" + url + ", " + sslConfigFileName + ")");
}
restClient = new RangerRESTClient(url, sslConfigFileName);
restClient.setRestClientConnTimeOutMs(restClientConnTimeOutMs);
restClient.setRestClientReadTimeOutMs(restClientReadTimeOutMs);
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminRESTClient.init(" + url + ", " + sslConfigFileName + ")");
}
}
private WebResource createWebResource(String url) {
WebResource ret = restClient.getResource(url);
return ret;
}
@Override
public ServiceTags getServiceTagsIfUpdated(final long lastKnownVersion, final long lastActivationTimeInMillis) throws Exception {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): ");
}
ServiceTags ret = null;
ClientResponse response = null;
WebResource webResource = null;
UserGroupInformation user = MiscUtil.getUGILoginUser();
boolean isSecureMode = isKerberosEnabled(user);
if (isSecureMode) {
PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() {
public ClientResponse run() {
WebResource secureWebResource = createWebResource(RangerRESTUtils.REST_URL_GET_SECURE_SERVICE_TAGS_IF_UPDATED + serviceName)
.queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion))
.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
return secureWebResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
}
};
if (LOG.isDebugEnabled()) {
LOG.debug("getServiceTagsIfUpdated as user " + user);
}
response = user.doAs(action);
} else {
webResource = createWebResource(RangerRESTUtils.REST_URL_GET_SERVICE_TAGS_IF_UPDATED + serviceName)
.queryParam(RangerRESTUtils.LAST_KNOWN_TAG_VERSION_PARAM, Long.toString(lastKnownVersion))
.queryParam(RangerRESTUtils.REST_PARAM_LAST_ACTIVATION_TIME, Long.toString(lastActivationTimeInMillis))
.queryParam(RangerRESTUtils.REST_PARAM_PLUGIN_ID, pluginId);
response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
}
if (response == null || response.getStatus() == HttpServletResponse.SC_NOT_MODIFIED) {
if (response == null) {
LOG.error("Error getting tags; Received NULL response!!. secureMode=" + isSecureMode + ", user=" + user + ", serviceName=" + serviceName);
} else {
RESTResponse resp = RESTResponse.fromClientResponse(response);
if (LOG.isDebugEnabled()) {
LOG.debug("No change in tags. secureMode=" + isSecureMode + ", user=" + user
+ ", response=" + resp + ", serviceName=" + serviceName
+ ", " + "lastKnownVersion=" + lastKnownVersion
+ ", " + "lastActivationTimeInMillis=" + lastActivationTimeInMillis);
}
}
ret = null;
} else if (response.getStatus() == HttpServletResponse.SC_OK) {
ret = response.getEntity(ServiceTags.class);
} else if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND) {
LOG.error("Error getting tags; service not found. secureMode=" + isSecureMode + ", user=" + user
+ ", response=" + response.getStatus() + ", serviceName=" + serviceName
+ ", " + "lastKnownVersion=" + lastKnownVersion
+ ", " + "lastActivationTimeInMillis=" + lastActivationTimeInMillis);
String exceptionMsg = response.hasEntity() ? response.getEntity(String.class) : null;
RangerServiceNotFoundException.throwExceptionIfServiceNotFound(serviceName, exceptionMsg);
LOG.warn("Received 404 error code with body:[" + exceptionMsg + "], Ignoring");
} else {
RESTResponse resp = RESTResponse.fromClientResponse(response);
LOG.warn("Error getting tags. secureMode=" + isSecureMode + ", user=" + user + ", response=" + resp + ", serviceName=" + serviceName);
ret = null;
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminRESTClient.getServiceTagsIfUpdated(" + lastKnownVersion + ", " + lastActivationTimeInMillis + "): ");
}
return ret;
}
@Override
public List<String> getTagTypes(String pattern) throws Exception {
if(LOG.isDebugEnabled()) {
LOG.debug("==> RangerAdminRESTClient.getTagTypes(" + pattern + "): ");
}
List<String> ret = null;
String emptyString = "";
UserGroupInformation user = MiscUtil.getUGILoginUser();
boolean isSecureMode = isKerberosEnabled(user);
final WebResource webResource = createWebResource(RangerRESTUtils.REST_URL_LOOKUP_TAG_NAMES)
.queryParam(RangerRESTUtils.SERVICE_NAME_PARAM, serviceName)
.queryParam(RangerRESTUtils.PATTERN_PARAM, pattern);
ClientResponse response = null;
if (isSecureMode) {
PrivilegedAction<ClientResponse> action = new PrivilegedAction<ClientResponse>() {
public ClientResponse run() {
return webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
}
};
if (LOG.isDebugEnabled()) {
LOG.debug("getTagTypes as user " + user);
}
response = user.doAs(action);
} else {
response = webResource.accept(RangerRESTUtils.REST_MIME_TYPE_JSON).get(ClientResponse.class);
}
if(response != null && response.getStatus() == HttpServletResponse.SC_OK) {
ret = response.getEntity(getGenericType(emptyString));
} else {
RESTResponse resp = RESTResponse.fromClientResponse(response);
LOG.error("Error getting tags. request=" + webResource
+ ", response=" + resp + ", serviceName=" + serviceName
+ ", " + "pattern=" + pattern);
throw new Exception(resp.getMessage());
}
if(LOG.isDebugEnabled()) {
LOG.debug("<== RangerAdminRESTClient.getTagTypes(" + pattern + "): " + ret);
}
return ret;
}
public boolean isKerberosEnabled(UserGroupInformation user) {
final boolean ret;
if (forceNonKerberos) {
ret = false;
} else {
ret = user != null && UserGroupInformation.isSecurityEnabled() && user.hasKerberosCredentials();
}
return ret;
}
}