You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by db...@apache.org on 2017/01/17 06:39:10 UTC
ambari git commit: AMBARI-19570. Hive View 2.0.0: Enable view of
ranger authorization for a table. (dipayanb)
Repository: ambari
Updated Branches:
refs/heads/branch-2.5 d54fab9ae -> 552c418bc
AMBARI-19570. Hive View 2.0.0: Enable view of ranger authorization for a table. (dipayanb)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/552c418b
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/552c418b
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/552c418b
Branch: refs/heads/branch-2.5
Commit: 552c418bc1f8971a2ef9b959fde30d51edf20df0
Parents: d54fab9
Author: Dipayan Bhowmick <di...@gmail.com>
Authored: Tue Jan 17 12:08:54 2017 +0530
Committer: Dipayan Bhowmick <di...@gmail.com>
Committed: Tue Jan 17 12:08:54 2017 +0530
----------------------------------------------------------------------
.../view/hive20/actor/MetaDataManager.java | 8 +-
.../hive20/resources/system/SystemService.java | 29 ++
.../system/ranger/RangerException.java | 56 ++++
.../resources/system/ranger/RangerService.java | 317 +++++++++++++++++++
.../view/hive20/utils/AuthorizationChecker.java | 74 +++++
.../resources/ui/app/adapters/application.js | 1 +
.../src/main/resources/ui/app/adapters/ping.js | 5 +
.../ui/app/configs/table-level-tabs.js | 6 +
.../hive20/src/main/resources/ui/app/router.js | 1 +
.../databases/database/tables/table/auth.js | 27 ++
.../src/main/resources/ui/app/styles/app.scss | 12 +
.../templates/components/table-properties.hbs | 2 +-
.../database/tables/table/auth-error.hbs | 35 ++
.../database/tables/table/auth-loading.hbs | 23 ++
.../databases/database/tables/table/auth.hbs | 53 ++++
.../views/hive20/src/main/resources/view.xml | 33 ++
16 files changed, 677 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
index 43733e4..525ec0d 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/actor/MetaDataManager.java
@@ -69,15 +69,15 @@ public class MetaDataManager extends HiveActor {
ActorRef databaseManager = databaseManagers.get(message.getUsername());
if (databaseManager == null) {
databaseManager = createDatabaseManager(message.getUsername(), message.getInstanceName());
- databaseManagers.put(context.getUsername(), databaseManager);
- databaseManager.tell(new DatabaseManager.Refresh(context.getUsername()), getSelf());
+ databaseManagers.put(message.getUsername(), databaseManager);
+ databaseManager.tell(new DatabaseManager.Refresh(message.getUsername()), getSelf());
} else {
if(message.isImmediate()) {
- databaseManager.tell(new DatabaseManager.Refresh(context.getUsername(), false), getSelf());
+ databaseManager.tell(new DatabaseManager.Refresh(message.getUsername(), false), getSelf());
}
cancelTerminationScheduler(message.getUsername());
}
- scheduleTermination(context.getUsername());
+ scheduleTermination(message.getUsername());
}
private void handleTerminate(Terminate message) {
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/SystemService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/SystemService.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/SystemService.java
index 0afe43c..1399ee4 100644
--- a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/SystemService.java
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/SystemService.java
@@ -22,16 +22,29 @@ import akka.actor.ActorRef;
import org.apache.ambari.view.hive20.BaseService;
import org.apache.ambari.view.hive20.ConnectionSystem;
import org.apache.ambari.view.hive20.actor.message.Ping;
+import org.apache.ambari.view.hive20.resources.system.ranger.RangerService;
+import org.json.simple.JSONObject;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
+import java.util.List;
/**
* System services which are required for the working of the application
*/
public class SystemService extends BaseService {
+ private final RangerService rangerService;
+
+ @Inject
+ public SystemService(RangerService rangerService) {
+ this.rangerService = rangerService;
+ }
+
/**
* Clients should sent pings to the server at regular interval so that the system could keep alive stuffs or do
* cleanup work when the pings stops
@@ -45,4 +58,20 @@ public class SystemService extends BaseService {
metaDataManager.tell(new Ping(context.getUsername(), context.getInstanceName()), ActorRef.noSender());
return Response.ok().status(Response.Status.NO_CONTENT).build();
}
+
+
+ /**
+ * Returns if the current user is a cluster operator or ambari administrator
+ */
+ @GET
+ @Path("/ranger/auth")
+ public Response rangerAuth(@QueryParam("database") String database,
+ @QueryParam("table") String table) {
+
+ List<RangerService.Policy> policies = rangerService.getPolicies(database, table);
+ JSONObject response = new JSONObject();
+ response.put("policies", policies);
+ return Response.ok(response).build();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerException.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerException.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerException.java
new file mode 100644
index 0000000..f32a997
--- /dev/null
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerException.java
@@ -0,0 +1,56 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view.hive20.resources.system.ranger;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Exceptions send by the Authorization API
+ */
+public class RangerException extends WebApplicationException {
+
+ public RangerException(String message, String errorCode, int status, Exception ex) {
+ super(errorEntity(message, errorCode, status, ex));
+ }
+
+ public RangerException(String message, String errorCode, int status) {
+ this(message, errorCode, status, null);
+ }
+
+ protected static Response errorEntity(String message, String errorCode, int status, Exception ex) {
+ Map<String, Object> response = new HashMap<String, Object>();
+ response.put("message", message);
+ response.put("errorCode", errorCode);
+ if (ex != null) {
+ response.put("trace", ExceptionUtils.getStackTrace(ex));
+ }
+
+ JSONObject finalResponse = new JSONObject();
+ finalResponse.put("errors", response);
+ return Response.status(status).entity(new JSONObject(finalResponse)).type(MediaType.APPLICATION_JSON).build();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerService.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerService.java
new file mode 100644
index 0000000..95ab27c
--- /dev/null
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/resources/system/ranger/RangerService.java
@@ -0,0 +1,317 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view.hive20.resources.system.ranger;
+
+import com.google.common.collect.Lists;
+import org.apache.ambari.view.AmbariHttpException;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.hive20.utils.AuthorizationChecker;
+import org.apache.ambari.view.utils.ambari.AmbariApi;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.apache.hadoop.hbase.util.Strings;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ */
+public class RangerService {
+
+ private static final String RANGER_CONFIG_URL = "/api/v1/clusters/%s/configurations/service_config_versions?service_name=RANGER&is_current=true";
+
+ protected final Logger LOG = LoggerFactory.getLogger(getClass());
+
+ private final AuthorizationChecker authChecker;
+ private final ViewContext context;
+
+ @Inject
+ public RangerService(AuthorizationChecker authChecker, ViewContext context) {
+ this.authChecker = authChecker;
+ this.context = context;
+ }
+
+ public List<Policy> getPolicies(String database, String table) {
+
+
+ if (context.getCluster() == null) {
+ return getPoliciesFromNonAmbariCluster(database, table);
+ } else {
+ if (!authChecker.isOperator()) {
+ LOG.error("User is not authorized to access the table authorization information");
+ throw new RangerException("User " + context.getUsername() + " does not have privilege to access the table authorization information", "NOT_OPERATOR_OR_ADMIN", 400);
+ }
+ return getPoliciesFromAmbariCluster(database, table);
+ }
+
+ }
+
+ private List<Policy> getPoliciesFromAmbariCluster(String database, String table) {
+ String rangerUrl = null;
+ try {
+ rangerUrl = getRangerUrlFromAmbari();
+ } catch (AmbariHttpException e) {
+ LOG.error("Failed to fetch Ranger URL from ambari. Exception: {}", e);
+ throw new RangerException("Failed to fetch Ranger URL from Ambari", "AMBARI_FETCH_FAILED", 500, e);
+ }
+ if (Strings.isEmpty(rangerUrl)) {
+ LOG.info("Ranger url is not configured for the instance");
+ throw new RangerException("Ranger url is not configured in Ambari.", "CONFIGURATION_ERROR", 500);
+ }
+
+ return getPoliciesFromRanger(rangerUrl, database, table);
+ }
+
+ private List<Policy> getPoliciesFromNonAmbariCluster(String database, String table) {
+ String rangerUrl = getRangerUrlFromConfig();
+ if (Strings.isEmpty(rangerUrl)) {
+ LOG.info("Ranger url is not configured for the instance");
+ throw new RangerException("Ranger url is not configured in Ambari Instance.", "CONFIGURATION_ERROR", 500);
+ }
+
+ return getPoliciesFromRanger(rangerUrl, database, table);
+ }
+
+ private List<Policy> getPoliciesFromRanger(String rangerUrl, String database, String table) {
+ RangerCred cred = getRangerCredFromConfig();
+ if (!cred.isValid()) {
+ LOG.info("Ranger username and password are not configured");
+ throw new RangerException("Bad ranger username/password", "CONFIGURATION_ERROR", 500);
+ }
+
+ String rangerResponse = fetchResponseFromRanger(rangerUrl, cred.username, cred.password, database, table);
+ if (Strings.isEmpty(rangerResponse)) {
+ return Lists.newArrayList();
+ }
+
+ return parseResponse(rangerResponse);
+ }
+
+ private List<Policy> parseResponse(String rangerResponse) {
+ JSONArray jsonArray = (JSONArray) JSONValue.parse(rangerResponse);
+ if (jsonArray.size() == 0) {
+ return new ArrayList<>();
+ }
+
+ List<Policy> policies = new ArrayList<>();
+
+ for (Object policy : jsonArray) {
+ JSONObject policyJson = (JSONObject) policy;
+ if ((Boolean) policyJson.get("isEnabled")) {
+ policies.add(parsePolicy(policyJson));
+ }
+ }
+
+ return policies;
+ }
+
+ private Policy parsePolicy(JSONObject policyJson) {
+ String name = (String) policyJson.get("name");
+ JSONArray policyItems = (JSONArray) policyJson.get("policyItems");
+ Policy policy = new Policy(name);
+
+ if (policyItems.size() > 0) {
+ JSONObject policyItem = (JSONObject) policyItems.get(0);
+ JSONArray usersJson = (JSONArray) policyItem.get("users");
+ JSONArray groupsJson = (JSONArray) policyItem.get("groups");
+
+
+ for (Object user : usersJson) {
+ policy.addUser((String) user);
+ }
+
+ for (Object group : groupsJson) {
+ policy.addGroup((String) group);
+ }
+ }
+
+
+ return policy;
+ }
+
+ private String fetchResponseFromRanger(String rangerUrl, String username, String password, String database, String table) {
+
+ String serviceName = context.getProperties().get("hive.ranger.servicename");
+ if(Strings.isEmpty(serviceName)) {
+ LOG.error("Bad service name configured");
+ throw new RangerException("Ranger service name is not configured in Ambari Instance.", "CONFIGURATION_ERROR", 500);
+ }
+
+ Map<String, String> headers = getRangerHeaders(username, password);
+ StringBuilder urlBuilder = getRangerUrl(rangerUrl, database, table, serviceName);
+
+ try {
+ InputStream stream = context.getURLStreamProvider().readFrom(urlBuilder.toString(), "GET", (String) null, headers);
+ if (stream == null) {
+ LOG.error("Ranger returned an empty stream.");
+ throw new RangerException("Ranger returned an empty stream.", "RANGER_ERROR", 500);
+ }
+ return IOUtils.toString(stream);
+ } catch (IOException e) {
+ LOG.error("Bad response from Ranger. Exception: {}", e);
+ throw new RangerException("Bad response from Ranger", "RANGER_ERROR", 500, e);
+ }
+ }
+
+ private StringBuilder getRangerUrl(String rangerUrl, String database, String table, String serviceName) {
+ StringBuilder queryParams = new StringBuilder();
+ if (!Strings.isEmpty(database)) {
+ queryParams.append("resource:database=");
+ queryParams.append(database);
+ if (!Strings.isEmpty(table)) {
+ queryParams.append("&");
+ }
+ }
+
+ if (!Strings.isEmpty(table)) {
+ queryParams.append("resource:table=");
+ queryParams.append(table);
+ }
+
+
+ String queryParamString = queryParams.toString();
+
+ StringBuilder urlBuilder = new StringBuilder();
+ urlBuilder.append(rangerUrl);
+ urlBuilder.append("/service/public/v2/api/service/");
+ urlBuilder.append(serviceName);
+ urlBuilder.append("/policy");
+ if (!Strings.isEmpty(queryParamString)) {
+ urlBuilder.append("?");
+ urlBuilder.append(queryParamString);
+ }
+ return urlBuilder;
+ }
+
+ private Map<String, String> getRangerHeaders(String username, String password) {
+ String authString = username + ":" + password;
+ byte[] authBytes = Base64.encodeBase64(authString.getBytes());
+ String auth = new String(authBytes);
+ Map<String, String> headers = new HashMap<>();
+ headers.put("Authorization", "Basic " + auth);
+ return headers;
+ }
+
+ private RangerCred getRangerCredFromConfig() {
+ return new RangerCred(context.getProperties().get("hive.ranger.username"),
+ context.getProperties().get("hive.ranger.password"));
+ }
+
+ public String getRangerUrlFromAmbari() throws AmbariHttpException {
+
+ AmbariApi ambariApi = new AmbariApi(context);
+ String url = String.format(RANGER_CONFIG_URL, context.getCluster().getName());
+ String config = ambariApi.readFromAmbari(url, "GET", null, null);
+ JSONObject configJson = (JSONObject) JSONValue.parse(config);
+ JSONArray itemsArray = (JSONArray) configJson.get("items");
+ if (itemsArray.size() == 0) {
+ LOG.error("Ranger service is not enabled in Ambari");
+ throw new RangerException("Ranger service is not enabled in Ambari", "SERVICE_ERROR", 500);
+ }
+ JSONObject item = (JSONObject) itemsArray.get(0);
+ JSONArray configurations = (JSONArray) item.get("configurations");
+ for (Object configuration : configurations) {
+ JSONObject configurationJson = (JSONObject) configuration;
+ String type = (String) configurationJson.get("type");
+ if (type.equalsIgnoreCase("admin-properties")) {
+ JSONObject properties = (JSONObject) configurationJson.get("properties");
+ return (String) properties.get("policymgr_external_url");
+ }
+ }
+ return null;
+ }
+
+ public String getRangerUrlFromConfig() {
+ return context.getProperties().get("hive.ranger.url");
+ }
+
+ /**
+ * POJO class to store the policy information from Ranger
+ */
+ public static class Policy {
+ private String name;
+ private List<String> users = new ArrayList<>();
+ private List<String> groups = new ArrayList<>();
+
+ public Policy(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<String> getUsers() {
+ return users;
+ }
+
+ public void setUsers(List<String> users) {
+ this.users = users;
+ }
+
+ public List<String> getGroups() {
+ return groups;
+ }
+
+ public void setGroups(List<String> groups) {
+ this.groups = groups;
+ }
+
+
+ public void addUser(String user) {
+ users.add(user);
+ }
+
+ public void addGroup(String group) {
+ groups.add(group);
+ }
+ }
+
+ /**
+ * POJO class to store the username and password for ranger access
+ */
+ private class RangerCred {
+ public String username;
+ public String password;
+
+ public RangerCred(String username, String password) {
+ this.username = username;
+ this.password = password;
+ }
+
+ public boolean isValid() {
+ return !(Strings.isEmpty(username) || Strings.isEmpty(password));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/AuthorizationChecker.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/AuthorizationChecker.java b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/AuthorizationChecker.java
new file mode 100644
index 0000000..3121ba0
--- /dev/null
+++ b/contrib/views/hive20/src/main/java/org/apache/ambari/view/hive20/utils/AuthorizationChecker.java
@@ -0,0 +1,74 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.ambari.view.hive20.utils;
+
+import org.apache.ambari.view.AmbariHttpException;
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.utils.ambari.AmbariApi;
+import org.apache.ambari.view.utils.ambari.NoClusterAssociatedException;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+
+/**
+ * Utility class to check the authorization of the user
+ */
+public class AuthorizationChecker {
+ protected final Logger LOG = LoggerFactory.getLogger(getClass());
+ private static final String AMBARI_OR_CLUSTER_ADMIN_PRIVILEGE_URL = "/api/v1/users/%s?privileges/PrivilegeInfo/permission_name=AMBARI.ADMINISTRATOR|" +
+ "(privileges/PrivilegeInfo/permission_name.in(CLUSTER.ADMINISTRATOR,CLUSTER.OPERATOR)&privileges/PrivilegeInfo/cluster_name=%s)";
+
+ private final ViewContext viewContext;
+ private final AmbariApi ambariApi;
+
+
+ @Inject
+ public AuthorizationChecker(ViewContext viewContext) {
+ this.viewContext = viewContext;
+ this.ambariApi = new AmbariApi(viewContext);
+ }
+
+ public boolean isOperator() {
+ if (viewContext.getCluster() == null) {
+ throw new NoClusterAssociatedException("No cluster is associated with the current instance");
+ }
+ String fetchUrl = String.format(AMBARI_OR_CLUSTER_ADMIN_PRIVILEGE_URL, viewContext.getUsername(), viewContext.getCluster().getName());
+
+ try {
+ String response = ambariApi.readFromAmbari(fetchUrl, "GET", null, null);
+
+ if (response != null && !response.isEmpty()) {
+ JSONObject json = (JSONObject) JSONValue.parse(response);
+ if (json.containsKey("privileges")) {
+ JSONArray privileges = (JSONArray) json.get("privileges");
+ if (privileges.size() > 0) return true;
+ }
+ }
+
+ } catch (AmbariHttpException e) {
+ LOG.error("Got Error response from url : {}. Response : {}", fetchUrl, e.getMessage(), e);
+ }
+
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js
index 82d53e4..c0189cc 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/application.js
@@ -56,6 +56,7 @@ export default DS.RESTAdapter.extend({
// by setting the proxyurl parameter in ember serve and for ambari to authenticate the requests, it needs this
// basic authorization. This is for default admin/admin username/password combination.
headers['Authorization'] = 'Basic YWRtaW46YWRtaW4=';
+ //headers['Authorization'] = 'Basic aGl2ZTpoaXZl';
}
return headers;
}),
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/adapters/ping.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/adapters/ping.js b/contrib/views/hive20/src/main/resources/ui/app/adapters/ping.js
index 20c6d9c..f88cfed 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/adapters/ping.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/adapters/ping.js
@@ -26,5 +26,10 @@ export default ApplicationAdapter.extend({
pathForType() {
return "system/ping";
+ },
+
+ fetchAuth(databaseName, tableName) {
+ const url = this.buildURL() + '/system/ranger/auth';
+ return this.ajax(url, "GET", {data: {database: databaseName, table: tableName}});
}
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/configs/table-level-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/configs/table-level-tabs.js b/contrib/views/hive20/src/main/resources/ui/app/configs/table-level-tabs.js
index 7a0cec1..ab7125a 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/configs/table-level-tabs.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/configs/table-level-tabs.js
@@ -60,6 +60,12 @@ let tableLevelTabs = [
label: 'STATISTICS',
link: 'databases.database.tables.table.stats',
faIcon: 'line-chart'
+ }),
+ Ember.Object.create({
+ name: 'authorization',
+ label: 'AUTHORIZATION',
+ link: 'databases.database.tables.table.auth',
+ faIcon: 'users'
})
];
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/router.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/router.js b/contrib/views/hive20/src/main/resources/ui/app/router.js
index 692cefd..e32dfe8 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/router.js
+++ b/contrib/views/hive20/src/main/resources/ui/app/router.js
@@ -42,6 +42,7 @@ Router.map(function() {
this.route('view');
this.route('ddl');
this.route('stats');
+ this.route('auth');
})
});
});
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/auth.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/auth.js b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/auth.js
new file mode 100644
index 0000000..ec9d1a2
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/routes/databases/database/tables/table/auth.js
@@ -0,0 +1,27 @@
+/**
+ * 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.
+ */
+
+import TableMetaRouter from './table-meta-router';
+
+export default TableMetaRouter.extend({
+ model(params, transition) {
+ let databaseName = transition.params['databases.database']['databaseId'];
+ let tableName = transition.params['databases.database.tables.table']['name'];
+ return this.store.adapterFor('ping').fetchAuth(databaseName, tableName);
+ }
+});
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
index 8e0ab21..5ae65d1 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
+++ b/contrib/views/hive20/src/main/resources/ui/app/styles/app.scss
@@ -805,6 +805,18 @@ pre {
}
+.loader {
+ padding-top: 25px;
+ padding-bottom: 25px;
+}
+
+.authorizations {
+ &.alert {
+ margin: 0;
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
index 0eaab5e..953ef84 100644
--- a/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/components/table-properties.hbs
@@ -33,7 +33,7 @@
{{/each}}
<tr class="new-settings text-center">
<td colspan="3">
- <a {{action "addNewRow"}}>{{fa-icon "plus"}} Add New Column</a>
+ <a {{action "addNewRow"}}>{{fa-icon "plus"}} Add New Properties</a>
</td>
</tr>
</tbody>
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-error.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-error.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-error.hbs
new file mode 100644
index 0000000..db3d3f2
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-error.hbs
@@ -0,0 +1,35 @@
+{{!
+* 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.
+}}
+
+<div class="row">
+ <div class="authorizations alert alert-info">
+ <p class="lead">{{fa-icon "shield" size=1}} Ranger policies</p>
+ </div>
+</div>
+<div class="row">
+ <div class="col-md-12 alert alert-danger">
+ <p><strong>Message:</strong> {{model.errors.message}}</p>
+ <p><strong>Error Code:</strong> {{model.errors.errorCode}}</p>
+ {{#if model.errors.trace}}
+ <p><strong>Trace:</strong></p>
+ <pre class="prettyprint">
+ {{model.errors.trace}}
+ </pre>
+ {{/if}}
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-loading.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-loading.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-loading.hbs
new file mode 100644
index 0000000..fbeb1a8
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth-loading.hbs
@@ -0,0 +1,23 @@
+{{!
+* 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.
+}}
+
+<div class="col-md-12 text-center loader">
+ {{fa-icon "spinner" spin=true size=3}}
+ <br>
+ <h3>Loading authorization information from Ranger</h3>
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth.hbs b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth.hbs
new file mode 100644
index 0000000..f717bcc
--- /dev/null
+++ b/contrib/views/hive20/src/main/resources/ui/app/templates/databases/database/tables/table/auth.hbs
@@ -0,0 +1,53 @@
+{{!
+* 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.
+}}
+<div class="row">
+ <div class="authorizations alert alert-info">
+ <p class="lead">{{fa-icon "shield" size=1}} Ranger policies</p>
+ </div>
+</div>
+
+<div class="row">
+ <table class="table table-bordered table-hover">
+ <thead>
+ <tr>
+ <th width="20%">POLICY NAME</th>
+ <th width="40%">USERS</th>
+ <th width="40%">GROUPS</th>
+ </tr>
+ </thead>
+ <tbody>
+ {{#each model.policies as |policy|}}
+ <tr>
+ <td>{{policy.name}}</td>
+ <td>
+ {{#each policy.users as |user|}}
+ <span class="label label-success">{{user}}</span>
+ {{/each}}
+ </td>
+ <td>
+ {{#each policy.groups as |group|}}
+ <span class="label label-success">{{group}}</span>
+ {{/each}}
+ </td>
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+</div>
+
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/552c418b/contrib/views/hive20/src/main/resources/view.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive20/src/main/resources/view.xml b/contrib/views/hive20/src/main/resources/view.xml
index 2cbfef0..7cbe15c 100644
--- a/contrib/views/hive20/src/main/resources/view.xml
+++ b/contrib/views/hive20/src/main/resources/view.xml
@@ -57,6 +57,30 @@
</parameter>
<parameter>
+ <name>hive.ranger.servicename</name>
+ <description>Set the service name of ranger configured for this hive cluster</description>
+ <label>Ranger Service Name</label>
+ <placeholder>c1_hive</placeholder>
+ <required>false</required>
+ </parameter>
+
+ <parameter>
+ <name>hive.ranger.username</name>
+ <description>Admin username for ranger</description>
+ <label>Ranger Username</label>
+ <default-value>admin</default-value>
+ <required>false</required>
+ </parameter>
+ <parameter>
+ <name>hive.ranger.password</name>
+ <description>Admin password for ranger</description>
+ <label>Ranger Password</label>
+ <default-value>admin</default-value>
+ <masked>true</masked>
+ <required>false</required>
+ </parameter>
+
+ <parameter>
<name>hive.metastore.warehouse.dir</name>
<description>Hive Metastore directory (example: /apps/hive/warehouse)</description>
<label>Hive Metastore directory</label>
@@ -149,6 +173,15 @@
</parameter>
<parameter>
+ <name>hive.ranger.url</name>
+ <description>Ranger URL</description>
+ <label>Ranger URL</label>
+ <placeholder>http://rangerhost:post</placeholder>
+ <cluster-config>fake</cluster-config>
+ <required>false</required>
+ </parameter>
+
+ <parameter>
<name>webhdfs.username</name>
<description>doAs for proxy user for HDFS. By default, uses the currently logged-in Ambari user.</description>
<label>WebHDFS Username</label>