Repository: ambari Updated Branches: refs/heads/branch-dev-patch-upgrade cd245c00a -> eb2c904e1
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/285666fa Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/285666fa Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/285666fa Branch: refs/heads/branch-dev-patch-upgrade Commit: 285666fac5a14f461950386d2687d172a3574283 Parents: badf9f7 Author: Dipayan Bhowmick <[email protected]> Authored: Tue Jan 17 12:08:54 2017 +0530 Committer: Dipayan Bhowmick <[email protected]> Committed: Tue Jan 17 12:09:27 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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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/285666fa/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>
