Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 8F432200BB3 for ; Wed, 2 Nov 2016 19:54:07 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 8DE33160AFB; Wed, 2 Nov 2016 18:54:07 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id D9CE4160AF0 for ; Wed, 2 Nov 2016 19:54:05 +0100 (CET) Received: (qmail 33471 invoked by uid 500); 2 Nov 2016 18:54:05 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 33461 invoked by uid 99); 2 Nov 2016 18:54:05 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Nov 2016 18:54:05 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id EB5B2E0A05; Wed, 2 Nov 2016 18:54:04 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: dbhowmick@apache.org To: commits@ambari.apache.org Message-Id: <3c01ddbf0a8d460faded8d74368bf020@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: ambari git commit: AMBARI-18670. Hive view 1.0/1.5 does not refresh LDAP credentials for user. (Ashwin Rajeev via dipayanb) Date: Wed, 2 Nov 2016 18:54:04 +0000 (UTC) archived-at: Wed, 02 Nov 2016 18:54:07 -0000 Repository: ambari Updated Branches: refs/heads/trunk d48b4639a -> e9b251210 AMBARI-18670. Hive view 1.0/1.5 does not refresh LDAP credentials for user. (Ashwin Rajeev via dipayanb) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/e9b25121 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/e9b25121 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/e9b25121 Branch: refs/heads/trunk Commit: e9b251210d2e3fb4265413229bc2dcd793f5bc3e Parents: d48b463 Author: Dipayan Bhowmick Authored: Thu Nov 3 00:23:03 2016 +0530 Committer: Dipayan Bhowmick Committed: Thu Nov 3 00:23:43 2016 +0530 ---------------------------------------------------------------------- .../ambari/view/hive2/ConnectionFactory.java | 19 ++- .../ambari/view/hive2/ConnectionSystem.java | 18 ++- .../ambari/view/hive2/actor/JdbcConnector.java | 4 +- .../view/hive2/client/AsyncJobRunner.java | 1 - .../view/hive2/client/AsyncJobRunnerImpl.java | 2 - .../view/hive2/client/ConnectionConfig.java | 7 +- .../ambari/view/hive2/internal/Connectable.java | 6 + .../hive2/internal/HiveConnectionWrapper.java | 18 +++ .../resources/browser/ConnectionService.java | 155 +++++++++++++++++++ .../resources/browser/HiveBrowserService.java | 4 +- .../view/hive2/resources/jobs/JobService.java | 31 ++-- .../app/controllers/index/history-query/logs.js | 22 ++- .../ui/hive-web/app/controllers/splash.js | 35 ++++- .../ui/hive-web/app/initializers/i18n.js | 1 + .../resources/ui/hive-web/app/routes/splash.js | 52 ++++++- .../resources/ui/hive-web/app/services/ldap.js | 59 +++++++ .../ui/hive-web/app/utils/constants.js | 1 + .../views/hive-next/src/main/resources/view.xml | 15 ++ 18 files changed, 409 insertions(+), 41 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java index 8fefe15..d333459 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionFactory.java @@ -20,6 +20,7 @@ package org.apache.ambari.view.hive2; import com.google.common.base.Function; import com.google.common.base.Joiner; +import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.FluentIterable; import org.apache.ambari.view.ViewContext; @@ -41,16 +42,25 @@ public class ConnectionFactory { private static final String HIVE_JDBC_URL_KEY = "hive.jdbc.url"; private static final String HIVE_SESSION_PARAMS = "hive.session.params"; + private static final String HIVE_LDAP_CONFIG = "hive.ldap.configured"; private static final String BINARY_PORT_KEY = "hive.server2.thrift.port"; + private static final String HIVE_AUTH_MODE = "hive.server2.authentication"; private static final String HTTP_PORT_KEY = "hive.server2.thrift.http.port"; private static final String HIVE_TRANSPORT_MODE_KEY = "hive.server2.transport.mode"; private static final String HTTP_PATH_KEY = "hive.server2.thrift.http.path"; private static final String HS2_PROXY_USER = "hive.server2.proxy.user"; private static final String USE_HIVE_INTERACTIVE_MODE = "use.hive.interactive.mode"; + public static boolean isLdapEnabled(ViewContext context){ + if (context.getCluster() == null) { + return context.getProperties().get(HIVE_LDAP_CONFIG).equalsIgnoreCase("true"); + } + return context.getCluster().getConfigurationValue(HIVE_SITE,HIVE_AUTH_MODE).equalsIgnoreCase("ldap"); + } + + public static ConnectionConfig create(ViewContext context) { - public static ConnectionConfig create(ViewContext context) { String jdbcUrl; if (context.getCluster() == null) { jdbcUrl = getConnectFromCustom(context); @@ -63,9 +73,16 @@ public class ConnectionFactory { } String userName = context.getUsername(); + if(isLdapEnabled(context)){ + Optional opPassword = ConnectionSystem.getInstance().getPassword(context); + if(opPassword.isPresent()){ + return new ConnectionConfig(userName, opPassword.get(), jdbcUrl); + } + } return new ConnectionConfig(userName, "", jdbcUrl); } + private static String getFromHiveConfiguration(ViewContext context) { boolean useLLAP = Boolean.valueOf(context.getProperties().get(USE_HIVE_INTERACTIVE_MODE)); String transportMode = context.getCluster().getConfigurationValue(HIVE_SITE, HIVE_TRANSPORT_MODE_KEY); http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java index 88ea3d7..4ec3332 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/ConnectionSystem.java @@ -23,7 +23,7 @@ import akka.actor.ActorSystem; import akka.actor.Inbox; import akka.actor.PoisonPill; import akka.actor.Props; -import com.google.common.collect.Multimap; +import com.google.common.base.Optional; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import org.apache.ambari.view.ViewContext; @@ -33,6 +33,7 @@ import org.apache.ambari.view.hive2.internal.ConnectionSupplier; import org.apache.ambari.view.hive2.internal.DataStorageSupplier; import org.apache.ambari.view.hive2.internal.HdfsApiSupplier; import org.apache.ambari.view.hive2.internal.SafeViewContext; +import org.apache.parquet.Strings; import java.util.HashMap; import java.util.Map; @@ -46,6 +47,9 @@ public class ConnectionSystem { private static final Object lock = new Object(); private static Map> operationControllerMap = new ConcurrentHashMap<>(); + // credentials map stores usernames and passwords + private static Map credentialsMap = new ConcurrentHashMap<>(); + private ConnectionSystem() { ClassLoader classLoader = getClass().getClassLoader(); Config config = ConfigFactory.load(classLoader); @@ -101,6 +105,18 @@ public class ConnectionSystem { return ref; } + public synchronized void persistCredentials(String user,String password){ + if(!Strings.isNullOrEmpty(password)){ + credentialsMap.put(user,password); + } + } + + + public synchronized Optional getPassword(ViewContext viewContext){ + String pass = credentialsMap.get(viewContext.getUsername()); + return Optional.fromNullable(pass); + } + public void removeOperationControllerFromCache(String viewInstanceName) { Map refs = operationControllerMap.remove(viewInstanceName); if (refs != null) { http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java index 2a2f8f7..bb438d2 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/actor/JdbcConnector.java @@ -349,7 +349,9 @@ public class JdbcConnector extends HiveActor { Optional connectionOptional = connectable.getConnection(); if (!connectionOptional.isPresent()) { - notifyConnectFailure(new SQLException("Hive connection is not created")); + SQLException sqlException = connectable.isUnauthorized() ? new SQLException("Hive Connection not Authorized", "AUTHFAIL") + : new SQLException("Hive connection is not created"); + notifyConnectFailure(sqlException); return false; } return true; http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java index 548dfae..421df8e 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunner.java @@ -20,7 +20,6 @@ package org.apache.ambari.view.hive2.client; import com.google.common.base.Optional; import org.apache.ambari.view.hive2.actor.message.SQLStatementJob; -import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed; import org.apache.ambari.view.hive2.actor.message.job.Failure; import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job; http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java index 286298a..182dfbc 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/AsyncJobRunnerImpl.java @@ -31,13 +31,11 @@ import org.apache.ambari.view.hive2.actor.message.FetchResult; import org.apache.ambari.view.hive2.actor.message.ResetCursor; import org.apache.ambari.view.hive2.actor.message.ResultNotReady; import org.apache.ambari.view.hive2.actor.message.SQLStatementJob; -import org.apache.ambari.view.hive2.actor.message.job.AsyncExecutionFailed; import org.apache.ambari.view.hive2.actor.message.job.CancelJob; import org.apache.ambari.view.hive2.actor.message.job.Failure; import org.apache.ambari.view.hive2.resources.jobs.viewJobs.Job; import org.apache.ambari.view.hive2.utils.ResultFetchFormattedException; import org.apache.ambari.view.hive2.utils.ResultNotReadyFormattedException; -import org.apache.ambari.view.hive2.utils.ServiceFormattedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import scala.concurrent.duration.Duration; http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java index 40cdd28..20f18ff 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/client/ConnectionConfig.java @@ -19,11 +19,10 @@ package org.apache.ambari.view.hive2.client; import org.apache.ambari.view.hive2.actor.message.Connect; -import org.apache.ambari.view.hive2.actor.message.HiveJob; public class ConnectionConfig { private final String username; - private final String password; + private String password; private final String jdbcUrl; public ConnectionConfig(String username, String password, String jdbcUrl) { @@ -32,6 +31,10 @@ public class ConnectionConfig { this.jdbcUrl = jdbcUrl; } + public void setPassword(String password) { + this.password = password; + } + public String getUsername() { return username; } http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java index 5bfb6dc..926decc 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/Connectable.java @@ -56,4 +56,10 @@ public interface Connectable { */ void disconnect() throws ConnectionException; + /** + * True when the connection is unauthorized + * @return + */ + boolean isUnauthorized(); + } http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java index 811df23..3701016 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/internal/HiveConnectionWrapper.java @@ -34,11 +34,13 @@ import java.sql.SQLException; public class HiveConnectionWrapper implements Connectable,Supplier { private static String DRIVER_NAME = "org.apache.hive.jdbc.HiveDriver"; + public static final String SUFFIX = "validating the login"; private final String jdbcUrl; private final String username; private final String password; private HiveConnection connection = null; + private boolean authFailed; public HiveConnectionWrapper(String jdbcUrl, String username, String password) { this.jdbcUrl = jdbcUrl; @@ -60,6 +62,8 @@ public class HiveConnectionWrapper implements Connectable,Supplier getConnection() { return Optional.fromNullable(connection); } http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/ConnectionService.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/ConnectionService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/ConnectionService.java new file mode 100644 index 0000000..eb1609d --- /dev/null +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/ConnectionService.java @@ -0,0 +1,155 @@ +/** + * 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.ambari.view.hive2.resources.browser; + +import com.google.common.base.Optional; +import com.google.common.collect.Maps; +import org.apache.ambari.view.ViewContext; +import org.apache.ambari.view.hive2.ConnectionFactory; +import org.apache.ambari.view.hive2.ConnectionSystem; +import org.apache.ambari.view.hive2.client.ConnectionConfig; +import org.apache.ambari.view.hive2.internal.ConnectionException; +import org.apache.ambari.view.hive2.internal.HiveConnectionWrapper; +import org.apache.ambari.view.hive2.utils.ServiceFormattedException; +import org.json.simple.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +/** + * Connection verification and management controller + */ +public class ConnectionService { + + public static final String NO_PASSWORD = ""; + public static final String SUFFIX = "validating the login"; + @Inject + protected ViewContext context; + + protected final static Logger LOG = + LoggerFactory.getLogger(ConnectionService.class); + + /** + * Check if LDAP is configured on Hive + * if no password is cached , ask for one(401) + * if yes and a password is cached, try + * to connect, if connection succeeds + * return OK, + * + * if connection fails - ask for one again(401) + */ + @GET + @Path("connect") + @Produces(MediaType.APPLICATION_JSON) + + public Response attemptConnection() { + boolean ldapEnabled = ConnectionFactory.isLdapEnabled(context); + if(ldapEnabled) { + ConnectionSystem instance = ConnectionSystem.getInstance(); + Optional password = instance.getPassword(context); + if (!password.isPresent()) { + // No password cached - request for one + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + // if there was a password cached, make a connection attempt + // get the password + String pass = password.get(); + // password may be stale, try to connect to Hive + return attemptHiveConnection(pass); + } + return attemptHiveConnection(NO_PASSWORD); + + } + + + private Response getOKResponse() { + JSONObject response = new JSONObject(); + response.put("message", "OK"); + response.put("trace", null); + response.put("status", "200"); + return Response.ok().entity(response).type(MediaType.APPLICATION_JSON).build(); + } + + private Response attemptHiveConnection(String pass) { + ConnectionConfig connectionConfig = ConnectionFactory.create(context); + HiveConnectionWrapper hiveConnectionWrapper = new HiveConnectionWrapper(connectionConfig.getJdbcUrl(), connectionConfig.getUsername(), pass); + try { + hiveConnectionWrapper.connect(); + } catch (ConnectionException e) { + // Cannot connect with the current credentials + // check the message to see if the cause was a login failure + // return a 401 + // else return a 500 + if(isLoginError(e)) + return Response.status(Response.Status.UNAUTHORIZED).build(); + else + throw new ServiceFormattedException(e.getMessage(), e); + } finally { + try { + hiveConnectionWrapper.disconnect(); + } + catch(ConnectionException e){ + LOG.warn("Cannot close the connection"); + } + } + return getOKResponse() ; + } + + private boolean isLoginError(ConnectionException ce) { + return ce.getCause().getMessage().toLowerCase().endsWith(SUFFIX); + } + + + /** + * Set password + * This just updates the caches. + */ + @POST + @Path("auth") + @Consumes(MediaType.APPLICATION_JSON) + public Response setupPassword(AuthRequest request) { + try { + //Cache the password for the user + ConnectionSystem instance = ConnectionSystem.getInstance(); + instance.persistCredentials(context.getUsername(),request.password); + return getOKResponse(); + } catch (WebApplicationException ex) { + throw ex; + } catch (Exception ex) { + throw new ServiceFormattedException(ex.getMessage(), ex); + } + } + + + + public static class AuthRequest { + public String password; + } + + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java index 7481f9e..ba9fe29 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/browser/HiveBrowserService.java @@ -74,9 +74,11 @@ public class HiveBrowserService { else like = "*" + like + "*"; JSONObject response = new JSONObject(); + ConnectionConfig hiveConnectionConfig = getHiveConnectionConfig(); DDLDelegator delegator = new DDLDelegatorImpl(context, ConnectionSystem.getInstance().getActorSystem(), ConnectionSystem.getInstance().getOperationController(context)); - List databases = delegator.getDbList(getHiveConnectionConfig(), like); + List databases = delegator.getDbList(hiveConnectionConfig, like); response.put("databases", databases); + return Response.ok(response).build(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java index f054a9d..ff315e4 100644 --- a/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java +++ b/contrib/views/hive-next/src/main/java/org/apache/ambari/view/hive2/resources/jobs/JobService.java @@ -23,6 +23,7 @@ import com.beust.jcommander.internal.Lists; import com.google.common.base.Optional; import org.apache.ambari.view.ViewResourceHandler; import org.apache.ambari.view.hive2.BaseService; +import org.apache.ambari.view.hive2.ConnectionFactory; import org.apache.ambari.view.hive2.ConnectionSystem; import org.apache.ambari.view.hive2.actor.message.job.Failure; import org.apache.ambari.view.hive2.backgroundjobs.BackgroundJobController; @@ -75,6 +76,7 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.InvocationTargetException; +import java.sql.SQLException; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -137,8 +139,15 @@ public class JobService extends BaseService { ConnectionSystem system = ConnectionSystem.getInstance(); final AsyncJobRunner asyncJobRunner = new AsyncJobRunnerImpl(context, system.getOperationController(context), system.getActorSystem()); Optional error = asyncJobRunner.getError(jobId, context.getUsername()); + if(error.isPresent()){ - throw new Exception(error.get().getError()); + Throwable th = error.get().getError(); + if(th instanceof SQLException){ + SQLException sqlException = (SQLException) th; + if(sqlException.getSQLState().equals("AUTHFAIL") && ConnectionFactory.isLdapEnabled(context)) + return Response.status(401).build(); + } + throw new Exception(th); } } @@ -543,27 +552,7 @@ public class JobService extends BaseService { } } - /** - * Set password and connect to Hive - */ - @POST - @Path("auth") - @Consumes(MediaType.APPLICATION_JSON) - public Response setupPassword(AuthRequest request) { - try { - /*HiveAuthCredentials authCredentials = new HiveAuthCredentials(); - authCredentials.setPassword(request.password); - new UserLocalHiveAuthCredentials().set(authCredentials, context);*/ - //connectionLocal.remove(context); // force reconnect on next get - //connectionLocal.get(context); - return Response.ok().status(200).build(); - } catch (WebApplicationException ex) { - throw ex; - } catch (Exception ex) { - throw new ServiceFormattedException(ex.getMessage(), ex); - } - } /** * Remove connection credentials http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js index 43c7a7e..2b5fd26 100644 --- a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js +++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/index/history-query/logs.js @@ -23,6 +23,7 @@ import utils from 'hive/utils/functions'; export default Ember.ObjectController.extend({ fileService: Ember.inject.service(constants.namingConventions.file), notifyService: Ember.inject.service(constants.namingConventions.notify), + ldapService: Ember.inject.service(constants.namingConventions.ldap), needs: [ constants.namingConventions.queryTabs, constants.namingConventions.index, @@ -32,12 +33,27 @@ export default Ember.ObjectController.extend({ index: Ember.computed.alias('controllers.' + constants.namingConventions.index), openQueries: Ember.computed.alias('controllers.' + constants.namingConventions.openQueries), + requestLdapPassword:function(callback) { + var ldap = this.get('ldapService'); + ldap.requestLdapPassword(this,callback); + }, + reloadJobLogs: function (job) { var self = this; var handleError = function (error) { job.set('isRunning', false); - - self.get('notifyService').error(error); + // Check if error is 401 + // show LDAP login and fail job + // show message to rerun job + if(error.status === 401){ + self.requestLdapPassword(function(){ + var err = { + message: Ember.I18n.t('alerts.success.query.rerun') + }; + self.get('notifyService').error(err); + }); + } else + self.get('notifyService').error(error); }; job.reload().then(function () { @@ -82,6 +98,8 @@ export default Ember.ObjectController.extend({ }); }, + + isJobRunning: function (job) { return utils.insensitiveCompare(job.get('status'), constants.statuses.unknown, http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js index 6f495ed..97b3ea6 100644 --- a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js +++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/controllers/splash.js @@ -22,9 +22,36 @@ import constants from 'hive/utils/constants'; export default Ember.Controller.extend({ databaseService: Ember.inject.service(constants.namingConventions.database), + ldapService: Ember.inject.service(constants.namingConventions.ldap), isExpanded: false, errors: "", stackTrace: "", + requestLdapPassword:function(callback) { + var ldap = this.get('ldapService'); + ldap.requestLdapPassword(this,callback); + }, + +checkConnection: function() { + var model = this.get('model'); + var url = this.container.lookup('adapter:application').buildURL() + '/resources/connection/'; + var finalurl = url + 'connect' ; + var self = this; + + return Ember.$.getJSON( finalurl ) + .then( + function(data) { + console.log("fulfil"); + model.set('ldapSuccess',true); + }, + function(reason) { + console.log("fail"); + if(reason.status === 401){ + model.set('ldapSuccess',false); + } + } + ); + + }, startTests: function() { var model = this.get('model'); @@ -64,9 +91,11 @@ export default Ember.Controller.extend({ model.set('percent', percent + 25); }; - var promises = ['hdfs', 'hiveserver', 'ats', 'userhome'].map(function(name) { - var finalurl = ((name == 'hiveserver') ? self.get('databaseService.baseUrl') : (url + name + 'Status')) || '' ; + + var promises = ['hdfs', 'ats', 'userhome'].map(function(name) { + + var finalurl = url + name + 'Status' ; return Ember.$.getJSON( finalurl ) .then( @@ -74,7 +103,7 @@ export default Ember.Controller.extend({ processResponse(name, data); }, function(reason) { - processResponse(name, reason.responseJSON); + processResponse(name, reason.responseJSON); } ); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js index a046b35..8459c83 100644 --- a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js +++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/initializers/i18n.js @@ -71,6 +71,7 @@ TRANSLATIONS = { }, query: { execution: 'Query has been submitted.', + rerun: "Password updated, please execute the query again", save: 'The query has been saved.', update: 'The query has been updated.' } http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js index b851bf1..6328256 100644 --- a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js +++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/routes/splash.js @@ -42,14 +42,54 @@ export default Ember.Route.extend({ controller.set('model', model); var self = this; - controller.startTests().then(function() { - if (model.get("hiveserverTest") && model.get("hdfsTest") && model.get("atsTest") && model.get("userhomeTest")) { - Ember.run.later(this, function() { - self.send('transition'); - }, 2000); - } + function loadView(){ + controller.startTests().then(function() { + + if (model.get("hiveserverTest") + && model.get("hdfsTest") + && model.get("atsTest") + && model.get("userhomeTest")) { + Ember.run.later(this, function() { + self.send('transition'); + }, 2000); + } + }); + } + + controller.checkConnection().then(function(){ + var percent = model.get('percent'); + model.set("hiveserverTest",true); + model.set("hiveserver" + 'TestDone', true); + model.set('percent', percent + 25); + loadView(); + },function(){ + if(!model.get('ldapSuccess')) { + var percent = model.get('percent'); + controller.requestLdapPassword(function(){ + // check the connection again + controller.checkConnection().then(function(){ + model.set("hiveserverTest",true); + model.set("hiveserver" + 'TestDone', true); + model.set('percent', percent + 25); + loadView(); + },function(){ + var percent = model.get('percent'); + var checkFailedMessage = "Hive authentication failed"; + var errors = controller.get("errors"); + errors += checkFailedMessage; + errors += '
'; + controller.set("errors", errors); + model.get("hiveserverTest",false); + model.set("hiveserver" + 'TestDone', true); + model.set('percent', percent + 25); + loadView(); + }); + }); + } }); + + }, actions: { http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/ldap.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/ldap.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/ldap.js new file mode 100644 index 0000000..4a3098b --- /dev/null +++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/services/ldap.js @@ -0,0 +1,59 @@ +/** + * 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 Ember from 'ember'; + +export default Ember.Service.extend({ + + requestLdapPassword: function (context, callback) { + + var url = context.container.lookup('adapter:application').buildURL() + '/resources/connection/'; + var defer = Ember.RSVP.defer(); + var self = context; + + self.send('openModal', 'modal-save', { + heading: "modals.authenticationLDAP.heading", + text: "", + type: "password", + defer: defer + }); + + return defer.promise.then(function (text) { + // make a post call with the given ldap password. + var password = text; + var ldapAuthURL = url + "auth"; + + $.ajax({ + url: ldapAuthURL, + type: 'post', + headers: {'X-Requested-With': 'XMLHttpRequest', 'X-Requested-By': 'ambari'}, + contentType: 'application/json', + data: JSON.stringify({"password": password}), + success: function (data, textStatus, jQxhr) { + console.log("LDAP done: " + data); + callback(); + }, + error: function (jqXhr, textStatus, errorThrown) { + console.log("LDAP fail: " + errorThrown); + self.get('notifyService').error("Wrong Credentials."); + } + }); + }); + + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js index eb1548e..348454b 100644 --- a/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js +++ b/contrib/views/hive-next/src/main/resources/ui/hive-web/app/utils/constants.js @@ -63,6 +63,7 @@ export default Ember.Object.create({ jobs: 'jobs', savedQuery: 'saved-query', database: 'database', + ldap:'ldap', databases: 'databases', openQueries: 'open-queries', visualExplain: 'visual-explain', http://git-wip-us.apache.org/repos/asf/ambari/blob/e9b25121/contrib/views/hive-next/src/main/resources/view.xml ---------------------------------------------------------------------- diff --git a/contrib/views/hive-next/src/main/resources/view.xml b/contrib/views/hive-next/src/main/resources/view.xml index 671591a..02e632c 100644 --- a/contrib/views/hive-next/src/main/resources/view.xml +++ b/contrib/views/hive-next/src/main/resources/view.xml @@ -48,6 +48,15 @@ + hive.ldap.configured + Set to true if Hive server is configured through LDAP + + false + false + false + + + hive.metastore.warehouse.dir Hive Metastore directory (example: /apps/hive/warehouse) @@ -291,6 +300,12 @@ org.apache.ambari.view.hive2.HelpService + + + connection + org.apache.ambari.view.hive2.resources.browser.ConnectionService + + org.apache.ambari.view.hive2.resources.jobs.viewJobs.JobImpl