sentry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From co...@apache.org
Subject sentry git commit: SENTRY-1348: Move HA related class from sentry-provider-db to sentry-service-common(Colin Ma, reviewed by Dapeng Sun)
Date Wed, 22 Jun 2016 05:27:55 GMT
Repository: sentry
Updated Branches:
  refs/heads/SENTRY-1205 aef769858 -> 4767ec38e


SENTRY-1348: Move HA related class from sentry-provider-db to sentry-service-common(Colin Ma, reviewed by Dapeng Sun)


Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/4767ec38
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/4767ec38
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/4767ec38

Branch: refs/heads/SENTRY-1205
Commit: 4767ec38ef2a5d967d37539c64c787c986afe5cb
Parents: aef7698
Author: Colin Ma <colin@apache.org>
Authored: Wed Jun 22 14:11:57 2016 +0800
Committer: Colin Ma <colin@apache.org>
Committed: Wed Jun 22 14:11:57 2016 +0800

----------------------------------------------------------------------
 sentry-provider/sentry-provider-db/pom.xml      |  17 --
 .../persistent/FixedJsonInstanceSerializer.java | 163 ------------
 .../db/service/persistent/HAContext.java        | 262 -------------------
 .../service/thrift/JaasConfiguration.java       | 133 ----------
 sentry-service/sentry-service-common/pom.xml    |  17 ++
 .../persistent/FixedJsonInstanceSerializer.java | 163 ++++++++++++
 .../db/service/persistent/HAContext.java        | 262 +++++++++++++++++++
 .../service/thrift/JaasConfiguration.java       | 133 ++++++++++
 8 files changed, 575 insertions(+), 575 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-provider/sentry-provider-db/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/pom.xml b/sentry-provider/sentry-provider-db/pom.xml
index f3029fa..3d76198 100644
--- a/sentry-provider/sentry-provider-db/pom.xml
+++ b/sentry-provider/sentry-provider-db/pom.xml
@@ -38,11 +38,6 @@ limitations under the License.
     </dependency>
     <dependency>
       <groupId>org.apache.hadoop</groupId>
-      <artifactId>hadoop-common</artifactId>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
     </dependency>
     <dependency>
@@ -166,18 +161,6 @@ limitations under the License.
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.apache.curator</groupId>
-      <artifactId>curator-recipes</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.curator</groupId>
-      <artifactId>curator-x-discovery</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.curator</groupId>
-      <artifactId>curator-test</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-pool2</artifactId>
     </dependency>

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java
deleted file mode 100644
index 476bf6a..0000000
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/**
- * 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.sentry.provider.db.service.persistent;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import org.codehaus.jackson.JsonNode;
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.map.DeserializationConfig;
-import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
-
-import com.google.common.base.Preconditions;
-import org.apache.curator.x.discovery.ServiceInstance;
-import org.apache.curator.x.discovery.ServiceInstanceBuilder;
-import org.apache.curator.x.discovery.ServiceType;
-import org.apache.curator.x.discovery.UriSpec;
-import org.apache.curator.x.discovery.details.InstanceSerializer;
-
-// TODO: Workaround for CURATOR-5 (https://issues.apache.org/jira/browse/CURATOR-5)
-// Remove this class (code from pull request listed on JIRA) and use regular JsonInstanceSerializer once fixed
-// (Otherwise we can't properly serialize objects for the ZK Service Discovery)
-public class FixedJsonInstanceSerializer<T> implements InstanceSerializer<T>
-{
-
-    private final ObjectMapper mMapper;
-    private final Class<T> mPayloadClass;
-
-    /**
-     * @param payloadClass
-     *            used to validate payloads when deserializing
-     */
-    public FixedJsonInstanceSerializer(final Class<T> payloadClass) {
-        this(payloadClass, new ObjectMapper());
-    }
-
-    public FixedJsonInstanceSerializer(final Class<T> pPayloadClass, final ObjectMapper pMapper) {
-        mPayloadClass = pPayloadClass;
-        mMapper = pMapper;
-        mMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
-    }
-
-    @Override
-    public byte[] serialize(final ServiceInstance<T> pInstance) throws Exception {
-        final ByteArrayOutputStream out = new ByteArrayOutputStream();
-        mMapper.writeValue(out, pInstance);
-        return out.toByteArray();
-
-    }
-
-    private String getTextField(final JsonNode pNode, final String pFieldName) {
-        Preconditions.checkNotNull(pNode);
-        Preconditions.checkNotNull(pFieldName);
-        return pNode.get(pFieldName) != null ? pNode.get(pFieldName).getTextValue() : null;
-    }
-
-    private Integer getIntegerField(final JsonNode pNode, final String pFieldName) {
-        Preconditions.checkNotNull(pNode);
-        Preconditions.checkNotNull(pFieldName);
-        return pNode.get(pFieldName) != null && pNode.get(pFieldName).isNumber() ? pNode.get(pFieldName)
-            .getIntValue() : null;
-    }
-
-    private Long getLongField(final JsonNode pNode, final String pFieldName) {
-        Preconditions.checkNotNull(pNode);
-        Preconditions.checkNotNull(pFieldName);
-        return pNode.get(pFieldName) != null && pNode.get(pFieldName).isLong() ? pNode.get(pFieldName).getLongValue()
-            : null;
-    }
-
-    private <O> O getObject(final JsonNode pNode, final String pFieldName, final Class<O> pObjectClass)
-        throws JsonParseException, JsonMappingException, IOException {
-        Preconditions.checkNotNull(pNode);
-        Preconditions.checkNotNull(pFieldName);
-        Preconditions.checkNotNull(pObjectClass);
-        if (pNode.get(pFieldName) != null && pNode.get(pFieldName).isObject()) {
-            return mMapper.readValue(pNode.get(pFieldName), pObjectClass);
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public ServiceInstance<T> deserialize(final byte[] pBytes) throws Exception {
-        final ByteArrayInputStream bais = new ByteArrayInputStream(pBytes);
-        final JsonNode rootNode = mMapper.readTree(bais);
-        final ServiceInstanceBuilder<T> builder = ServiceInstance.builder();
-        {
-            final String address = getTextField(rootNode, "address");
-            if (address != null) {
-                builder.address(address);
-            }
-        }
-        {
-            final String id = getTextField(rootNode, "id");
-            if (id != null) {
-                builder.id(id);
-            }
-        }
-        {
-            final String name = getTextField(rootNode, "name");
-            if (name != null) {
-                builder.name(name);
-            }
-        }
-        {
-            final Integer port = getIntegerField(rootNode, "port");
-            if (port != null) {
-                builder.port(port);
-            }
-        }
-        {
-            final Integer sslPort = getIntegerField(rootNode, "sslPort");
-            if (sslPort != null) {
-                builder.sslPort(sslPort);
-            }
-        }
-        {
-            final Long registrationTimeUTC = getLongField(rootNode, "registrationTimeUTC");
-            if (registrationTimeUTC != null) {
-                builder.registrationTimeUTC(registrationTimeUTC);
-            }
-        }
-        {
-            final T payload = getObject(rootNode, "payload", mPayloadClass);
-            if (payload != null) {
-                builder.payload(payload);
-            }
-        }
-        {
-            final ServiceType serviceType = getObject(rootNode, "serviceType", ServiceType.class);
-            if (serviceType != null) {
-                builder.serviceType(serviceType);
-            }
-        }
-        {
-            final UriSpec uriSpec = getObject(rootNode, "uriSpec", UriSpec.class);
-            if (uriSpec != null) {
-                builder.uriSpec(uriSpec);
-            }
-        }
-        return builder.build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
deleted file mode 100644
index cacc29f..0000000
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * 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.sentry.provider.db.service.persistent;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.curator.RetryPolicy;
-import org.apache.curator.framework.CuratorFramework;
-import org.apache.curator.framework.CuratorFrameworkFactory;
-import org.apache.curator.framework.api.ACLProvider;
-import org.apache.curator.framework.imps.CuratorFrameworkState;
-import org.apache.curator.framework.imps.DefaultACLProvider;
-import org.apache.curator.retry.RetryNTimes;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.security.SecurityUtil;
-import org.apache.sentry.service.thrift.JaasConfiguration;
-import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
-import org.apache.zookeeper.ZooDefs.Perms;
-import org.apache.zookeeper.client.ZooKeeperSaslClient;
-import org.apache.zookeeper.data.ACL;
-import org.apache.zookeeper.data.Id;
-import org.apache.zookeeper.data.Stat;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-
-/**
- * Stores the HA related context
- */
-public class HAContext {
-
-  private static final Logger LOGGER = LoggerFactory.getLogger(HAContext.class);
-  private static volatile HAContext serverHAContext = null;
-  private static boolean aclChecked = false;
-
-  public final static String SENTRY_SERVICE_REGISTER_NAMESPACE = "sentry-service";
-  public static final String SENTRY_ZK_JAAS_NAME = "SentryClient";
-  private final String zookeeperQuorum;
-  private final int retriesMaxCount;
-  private final int sleepMsBetweenRetries;
-  private final String namespace;
-
-  private final boolean zkSecure;
-  private List<ACL> saslACL;
-
-  private final CuratorFramework curatorFramework;
-  private final RetryPolicy retryPolicy;
-
-  protected HAContext(Configuration conf) throws Exception {
-    this.zookeeperQuorum = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM_DEFAULT);
-    this.retriesMaxCount = conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT_DEFAULT);
-    this.sleepMsBetweenRetries = conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS_DEFAULT);
-    this.namespace = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_NAMESPACE,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_NAMESPACE_DEFAULT);
-    this.zkSecure = conf.getBoolean(ServerConfig.SENTRY_HA_ZOOKEEPER_SECURITY,
-        ServerConfig.SENTRY_HA_ZOOKEEPER_SECURITY_DEFAULT);
-    ACLProvider aclProvider;
-    validateConf();
-    if (zkSecure) {
-      LOGGER.info("Connecting to ZooKeeper with SASL/Kerberos and using 'sasl' ACLs");
-      setJaasConfiguration(conf);
-      System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
-          SENTRY_ZK_JAAS_NAME);
-      saslACL = Lists.newArrayList();
-      saslACL.add(new ACL(Perms.ALL, new Id("sasl", getServicePrincipal(conf,
-          ServerConfig.PRINCIPAL))));
-      saslACL.add(new ACL(Perms.ALL, new Id("sasl", getServicePrincipal(conf,
-              ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_PRINCIPAL))));
-      aclProvider = new SASLOwnerACLProvider();
-      String allowConnect = conf.get(ServerConfig.ALLOW_CONNECT);
-
-      if (!Strings.isNullOrEmpty(allowConnect)) {
-        for (String principal : Arrays.asList(allowConnect.split("\\s*,\\s*"))) {
-          LOGGER.info("Adding acls for " + principal);
-          saslACL.add(new ACL(Perms.ALL, new Id("sasl", principal)));
-        }
-      }
-    } else {
-      LOGGER.info("Connecting to ZooKeeper without authentication");
-      aclProvider = new DefaultACLProvider();
-    }
-
-    retryPolicy = new RetryNTimes(retriesMaxCount, sleepMsBetweenRetries);
-    this.curatorFramework = CuratorFrameworkFactory.builder()
-        .namespace(this.namespace)
-        .connectString(this.zookeeperQuorum)
-        .retryPolicy(retryPolicy)
-        .aclProvider(aclProvider)
-        .build();
-    startCuratorFramework();
-  }
-
-  /**
-   * Use common HAContext (ie curator framework connection to ZK)
-   *
-   * @param conf
-   * @throws Exception
-   */
-  public static HAContext getHAContext(Configuration conf) throws Exception {
-    if (serverHAContext == null) {
-      serverHAContext = new HAContext(conf);
-      Runtime.getRuntime().addShutdownHook(new Thread() {
-        @Override
-        public void run() {
-          LOGGER.info("ShutdownHook closing curator framework");
-          try {
-            clearServerContext();
-          } catch (Throwable t) {
-            LOGGER.error("Error stopping SentryService", t);
-          }
-        }
-      });
-
-    }
-    return serverHAContext;
-  }
-
-  // HA context for server which verifies the ZK ACLs on namespace
-  public static HAContext getHAServerContext(Configuration conf) throws Exception {
-    HAContext serverContext = getHAContext(conf);
-    serverContext.checkAndSetACLs();
-    return serverContext;
-  }
-
-  @VisibleForTesting
-  public static synchronized void clearServerContext() {
-    if (serverHAContext != null) {
-      serverHAContext.getCuratorFramework().close();
-      serverHAContext = null;
-    }
-  }
-
-  public void startCuratorFramework() {
-    if (curatorFramework.getState() != CuratorFrameworkState.STARTED) {
-      curatorFramework.start();
-    }
-  }
-
-  public CuratorFramework getCuratorFramework() {
-    return this.curatorFramework;
-  }
-
-  public String getZookeeperQuorum() {
-    return zookeeperQuorum;
-  }
-
-  public static boolean isHaEnabled(Configuration conf) {
-    return conf.getBoolean(ServerConfig.SENTRY_HA_ENABLED, ServerConfig.SENTRY_HA_ENABLED_DEFAULT);
-  }
-
-  public String getNamespace() {
-    return namespace;
-  }
-
-  public RetryPolicy getRetryPolicy() {
-    return retryPolicy;
-  }
-
-  private void validateConf() {
-    Preconditions.checkNotNull(zookeeperQuorum, "Zookeeper Quorum should not be null.");
-    Preconditions.checkNotNull(namespace, "Zookeeper namespace should not be null.");
-  }
-
-  protected String getServicePrincipal(Configuration conf, String confProperty)
-      throws IOException {
-    String principal = conf.get(confProperty);
-    Preconditions.checkNotNull(principal);
-    Preconditions.checkArgument(principal.length() != 0, "Server principal is not right.");
-    return principal.split("[/@]")[0];
-  }
-
-  private void checkAndSetACLs() throws Exception {
-    if (zkSecure && !aclChecked) {
-      // If znodes were previously created without security enabled, and now it is, we need to go through all existing znodes
-      // and set the ACLs for them. This is done just once at the startup
-      // We can't get the namespace znode through curator; have to go through zk client
-      startCuratorFramework();
-      String newNamespace = "/" + curatorFramework.getNamespace();
-      if (curatorFramework.getZookeeperClient().getZooKeeper().exists(newNamespace, null) != null) {
-        List<ACL> acls = curatorFramework.getZookeeperClient().getZooKeeper().getACL(newNamespace, new Stat());
-        if (acls.isEmpty() || !acls.get(0).getId().getScheme().equals("sasl")) {
-          LOGGER.info("'sasl' ACLs not set; setting...");
-          List<String> children = curatorFramework.getZookeeperClient().getZooKeeper().getChildren(newNamespace, null);
-          for (String child : children) {
-            checkAndSetACLs("/" + child);
-          }
-          curatorFramework.getZookeeperClient().getZooKeeper().setACL(newNamespace, saslACL, -1);
-        }
-      }
-      aclChecked = true;
-
-    }
-  }
-
-  private void checkAndSetACLs(String path) throws Exception {
-      LOGGER.info("Setting acls on " + path);
-      List<String> children = curatorFramework.getChildren().forPath(path);
-      for (String child : children) {
-        checkAndSetACLs(path + "/" + child);
-      }
-      curatorFramework.setACL().withACL(saslACL).forPath(path);
-  }
-
-  // This gets ignored during most tests, see ZKXTestCaseWithSecurity#setupZKServer()
-  private void setJaasConfiguration(Configuration conf) throws IOException {
-    if ("false".equalsIgnoreCase(conf.get(
-          ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_TICKET_CACHE,
-          ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_TICKET_CACHE_DEFAULT))) {
-      String keytabFile = conf.get(ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_KEYTAB);
-      Preconditions.checkArgument(keytabFile.length() != 0, "Keytab File is not right.");
-      String principal = conf.get(ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_PRINCIPAL);
-      principal = SecurityUtil.getServerPrincipal(principal,
-        conf.get(ServerConfig.RPC_ADDRESS, ServerConfig.RPC_ADDRESS_DEFAULT));
-      Preconditions.checkArgument(principal.length() != 0, "Kerberos principal is not right.");
-
-      // This is equivalent to writing a jaas.conf file and setting the system property, "java.security.auth.login.config", to
-      // point to it (but this way we don't have to write a file, and it works better for the tests)
-      JaasConfiguration.addEntryForKeytab(SENTRY_ZK_JAAS_NAME, principal, keytabFile);
-    } else {
-      // Create jaas conf for ticket cache
-      JaasConfiguration.addEntryForTicketCache(SENTRY_ZK_JAAS_NAME);
-    }
-    javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
-  }
-
-  public class SASLOwnerACLProvider implements ACLProvider {
-    @Override
-    public List<ACL> getDefaultAcl() {
-        return saslACL;
-    }
-
-    @Override
-    public List<ACL> getAclForPath(String path) {
-        return saslACL;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java
deleted file mode 100644
index a79ce5f..0000000
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * 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.sentry.service.thrift;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.security.auth.login.AppConfigurationEntry;
-import javax.security.auth.login.Configuration;
-
-/**
- * Creates a programmatic version of a jaas.conf file.  This can be used instead of writing a jaas.conf file and setting
- * the system property, "java.security.auth.login.config", to point to that file.  It is meant to be used for connecting to
- * ZooKeeper.
- * <p>
- * example usage:
- * JaasConfiguration.addEntry("Client", principal, keytabFile);
- * javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
- */
-public final class JaasConfiguration extends Configuration {
-  private static Map<String, AppConfigurationEntry> entries = new HashMap<String, AppConfigurationEntry>();
-  private static JaasConfiguration me = null;
-  private static final String krb5LoginModuleName;
-
-  static  {
-    if (System.getProperty("java.vendor").contains("IBM")) {
-      krb5LoginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
-    }
-    else {
-      krb5LoginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
-    }
-  }
-
-  private JaasConfiguration() {
-    // don't need to do anything here but we want to make it private
-  }
-
-  /**
-   * Return the singleton.  You'd typically use it only to do this:
-   * <p>
-   * javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
-   *
-   * @return
-   */
-  public static Configuration getInstance() {
-    if (me == null) {
-      me = new JaasConfiguration();
-    }
-    return me;
-  }
-
-  /**
-   * Add an entry to the jaas configuration with the passed in name, principal, and keytab.  The other necessary options will be
-   * set for you.
-   *
-   * @param name The name of the entry (e.g. "Client")
-   * @param principal The principal of the user
-   * @param keytab The location of the keytab
-   */
-  public static void addEntryForKeytab(String name, String principal, String keytab) {
-    Map<String, String> options = new HashMap<String, String>();
-    options.put("keyTab", keytab);
-    options.put("principal", principal);
-    options.put("useKeyTab", "true");
-    options.put("storeKey", "true");
-    options.put("useTicketCache", "false");
-    AppConfigurationEntry entry = new AppConfigurationEntry(krb5LoginModuleName,
-        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
-    entries.put(name, entry);
-  }
-
-  /**
-   * Add an entry to the jaas configuration with the passed in name. The other
-   * necessary options will be set for you.
-   *
-   * @param name The name of the entry (e.g. "Client")
-   */
-  public static void addEntryForTicketCache(String sectionName) {
-    Map<String, String> options = new HashMap<String, String>();
-    options.put("useKeyTab", "false");
-    options.put("storeKey", "false");
-    options.put("useTicketCache", "true");
-    AppConfigurationEntry entry = new AppConfigurationEntry(krb5LoginModuleName,
-        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
-    entries.put(sectionName, entry);
-  }
-
-  /**
-   * Removes the specified entry.
-   *
-   * @param name  The name of the entry to remove
-   */
-  public static void removeEntry(String name) {
-    entries.remove(name);
-  }
-
-  /**
-   * Clears all entries.
-   */
-  public static void clearEntries() {
-    entries.clear();
-  }
-
-  /**
-   * Returns the entries map.
-   *
-   * @return the entries map
-   */
-  public static Map<String, AppConfigurationEntry> getEntries() {
-    return entries;
-  }
-
-  @Override
-  public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
-    return new AppConfigurationEntry[]{entries.get(name)};
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-service/sentry-service-common/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-common/pom.xml b/sentry-service/sentry-service-common/pom.xml
index d47cafa..512c341 100644
--- a/sentry-service/sentry-service-common/pom.xml
+++ b/sentry-service/sentry-service-common/pom.xml
@@ -52,6 +52,23 @@ limitations under the License.
       <groupId>org.apache.sentry</groupId>
       <artifactId>sentry-core-common</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.curator</groupId>
+      <artifactId>curator-recipes</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.curator</groupId>
+      <artifactId>curator-x-discovery</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.curator</groupId>
+      <artifactId>curator-test</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hadoop</groupId>
+      <artifactId>hadoop-common</artifactId>
+      <scope>provided</scope>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java b/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java
new file mode 100644
index 0000000..476bf6a
--- /dev/null
+++ b/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/FixedJsonInstanceSerializer.java
@@ -0,0 +1,163 @@
+/**
+ * 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.sentry.provider.db.service.persistent;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.DeserializationConfig;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import com.google.common.base.Preconditions;
+import org.apache.curator.x.discovery.ServiceInstance;
+import org.apache.curator.x.discovery.ServiceInstanceBuilder;
+import org.apache.curator.x.discovery.ServiceType;
+import org.apache.curator.x.discovery.UriSpec;
+import org.apache.curator.x.discovery.details.InstanceSerializer;
+
+// TODO: Workaround for CURATOR-5 (https://issues.apache.org/jira/browse/CURATOR-5)
+// Remove this class (code from pull request listed on JIRA) and use regular JsonInstanceSerializer once fixed
+// (Otherwise we can't properly serialize objects for the ZK Service Discovery)
+public class FixedJsonInstanceSerializer<T> implements InstanceSerializer<T>
+{
+
+    private final ObjectMapper mMapper;
+    private final Class<T> mPayloadClass;
+
+    /**
+     * @param payloadClass
+     *            used to validate payloads when deserializing
+     */
+    public FixedJsonInstanceSerializer(final Class<T> payloadClass) {
+        this(payloadClass, new ObjectMapper());
+    }
+
+    public FixedJsonInstanceSerializer(final Class<T> pPayloadClass, final ObjectMapper pMapper) {
+        mPayloadClass = pPayloadClass;
+        mMapper = pMapper;
+        mMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+    }
+
+    @Override
+    public byte[] serialize(final ServiceInstance<T> pInstance) throws Exception {
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        mMapper.writeValue(out, pInstance);
+        return out.toByteArray();
+
+    }
+
+    private String getTextField(final JsonNode pNode, final String pFieldName) {
+        Preconditions.checkNotNull(pNode);
+        Preconditions.checkNotNull(pFieldName);
+        return pNode.get(pFieldName) != null ? pNode.get(pFieldName).getTextValue() : null;
+    }
+
+    private Integer getIntegerField(final JsonNode pNode, final String pFieldName) {
+        Preconditions.checkNotNull(pNode);
+        Preconditions.checkNotNull(pFieldName);
+        return pNode.get(pFieldName) != null && pNode.get(pFieldName).isNumber() ? pNode.get(pFieldName)
+            .getIntValue() : null;
+    }
+
+    private Long getLongField(final JsonNode pNode, final String pFieldName) {
+        Preconditions.checkNotNull(pNode);
+        Preconditions.checkNotNull(pFieldName);
+        return pNode.get(pFieldName) != null && pNode.get(pFieldName).isLong() ? pNode.get(pFieldName).getLongValue()
+            : null;
+    }
+
+    private <O> O getObject(final JsonNode pNode, final String pFieldName, final Class<O> pObjectClass)
+        throws JsonParseException, JsonMappingException, IOException {
+        Preconditions.checkNotNull(pNode);
+        Preconditions.checkNotNull(pFieldName);
+        Preconditions.checkNotNull(pObjectClass);
+        if (pNode.get(pFieldName) != null && pNode.get(pFieldName).isObject()) {
+            return mMapper.readValue(pNode.get(pFieldName), pObjectClass);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ServiceInstance<T> deserialize(final byte[] pBytes) throws Exception {
+        final ByteArrayInputStream bais = new ByteArrayInputStream(pBytes);
+        final JsonNode rootNode = mMapper.readTree(bais);
+        final ServiceInstanceBuilder<T> builder = ServiceInstance.builder();
+        {
+            final String address = getTextField(rootNode, "address");
+            if (address != null) {
+                builder.address(address);
+            }
+        }
+        {
+            final String id = getTextField(rootNode, "id");
+            if (id != null) {
+                builder.id(id);
+            }
+        }
+        {
+            final String name = getTextField(rootNode, "name");
+            if (name != null) {
+                builder.name(name);
+            }
+        }
+        {
+            final Integer port = getIntegerField(rootNode, "port");
+            if (port != null) {
+                builder.port(port);
+            }
+        }
+        {
+            final Integer sslPort = getIntegerField(rootNode, "sslPort");
+            if (sslPort != null) {
+                builder.sslPort(sslPort);
+            }
+        }
+        {
+            final Long registrationTimeUTC = getLongField(rootNode, "registrationTimeUTC");
+            if (registrationTimeUTC != null) {
+                builder.registrationTimeUTC(registrationTimeUTC);
+            }
+        }
+        {
+            final T payload = getObject(rootNode, "payload", mPayloadClass);
+            if (payload != null) {
+                builder.payload(payload);
+            }
+        }
+        {
+            final ServiceType serviceType = getObject(rootNode, "serviceType", ServiceType.class);
+            if (serviceType != null) {
+                builder.serviceType(serviceType);
+            }
+        }
+        {
+            final UriSpec uriSpec = getObject(rootNode, "uriSpec", UriSpec.class);
+            if (uriSpec != null) {
+                builder.uriSpec(uriSpec);
+            }
+        }
+        return builder.build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java b/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
new file mode 100644
index 0000000..cacc29f
--- /dev/null
+++ b/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/provider/db/service/persistent/HAContext.java
@@ -0,0 +1,262 @@
+/**
+ * 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.sentry.provider.db.service.persistent;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.curator.RetryPolicy;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.api.ACLProvider;
+import org.apache.curator.framework.imps.CuratorFrameworkState;
+import org.apache.curator.framework.imps.DefaultACLProvider;
+import org.apache.curator.retry.RetryNTimes;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.SecurityUtil;
+import org.apache.sentry.service.thrift.JaasConfiguration;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.zookeeper.ZooDefs.Perms;
+import org.apache.zookeeper.client.ZooKeeperSaslClient;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+import org.apache.zookeeper.data.Stat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+
+/**
+ * Stores the HA related context
+ */
+public class HAContext {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(HAContext.class);
+  private static volatile HAContext serverHAContext = null;
+  private static boolean aclChecked = false;
+
+  public final static String SENTRY_SERVICE_REGISTER_NAMESPACE = "sentry-service";
+  public static final String SENTRY_ZK_JAAS_NAME = "SentryClient";
+  private final String zookeeperQuorum;
+  private final int retriesMaxCount;
+  private final int sleepMsBetweenRetries;
+  private final String namespace;
+
+  private final boolean zkSecure;
+  private List<ACL> saslACL;
+
+  private final CuratorFramework curatorFramework;
+  private final RetryPolicy retryPolicy;
+
+  protected HAContext(Configuration conf) throws Exception {
+    this.zookeeperQuorum = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
+        ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM_DEFAULT);
+    this.retriesMaxCount = conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT,
+        ServerConfig.SENTRY_HA_ZOOKEEPER_RETRIES_MAX_COUNT_DEFAULT);
+    this.sleepMsBetweenRetries = conf.getInt(ServerConfig.SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS,
+        ServerConfig.SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS_DEFAULT);
+    this.namespace = conf.get(ServerConfig.SENTRY_HA_ZOOKEEPER_NAMESPACE,
+        ServerConfig.SENTRY_HA_ZOOKEEPER_NAMESPACE_DEFAULT);
+    this.zkSecure = conf.getBoolean(ServerConfig.SENTRY_HA_ZOOKEEPER_SECURITY,
+        ServerConfig.SENTRY_HA_ZOOKEEPER_SECURITY_DEFAULT);
+    ACLProvider aclProvider;
+    validateConf();
+    if (zkSecure) {
+      LOGGER.info("Connecting to ZooKeeper with SASL/Kerberos and using 'sasl' ACLs");
+      setJaasConfiguration(conf);
+      System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY,
+          SENTRY_ZK_JAAS_NAME);
+      saslACL = Lists.newArrayList();
+      saslACL.add(new ACL(Perms.ALL, new Id("sasl", getServicePrincipal(conf,
+          ServerConfig.PRINCIPAL))));
+      saslACL.add(new ACL(Perms.ALL, new Id("sasl", getServicePrincipal(conf,
+              ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_PRINCIPAL))));
+      aclProvider = new SASLOwnerACLProvider();
+      String allowConnect = conf.get(ServerConfig.ALLOW_CONNECT);
+
+      if (!Strings.isNullOrEmpty(allowConnect)) {
+        for (String principal : Arrays.asList(allowConnect.split("\\s*,\\s*"))) {
+          LOGGER.info("Adding acls for " + principal);
+          saslACL.add(new ACL(Perms.ALL, new Id("sasl", principal)));
+        }
+      }
+    } else {
+      LOGGER.info("Connecting to ZooKeeper without authentication");
+      aclProvider = new DefaultACLProvider();
+    }
+
+    retryPolicy = new RetryNTimes(retriesMaxCount, sleepMsBetweenRetries);
+    this.curatorFramework = CuratorFrameworkFactory.builder()
+        .namespace(this.namespace)
+        .connectString(this.zookeeperQuorum)
+        .retryPolicy(retryPolicy)
+        .aclProvider(aclProvider)
+        .build();
+    startCuratorFramework();
+  }
+
+  /**
+   * Use common HAContext (ie curator framework connection to ZK)
+   *
+   * @param conf
+   * @throws Exception
+   */
+  public static HAContext getHAContext(Configuration conf) throws Exception {
+    if (serverHAContext == null) {
+      serverHAContext = new HAContext(conf);
+      Runtime.getRuntime().addShutdownHook(new Thread() {
+        @Override
+        public void run() {
+          LOGGER.info("ShutdownHook closing curator framework");
+          try {
+            clearServerContext();
+          } catch (Throwable t) {
+            LOGGER.error("Error stopping SentryService", t);
+          }
+        }
+      });
+
+    }
+    return serverHAContext;
+  }
+
+  // HA context for server which verifies the ZK ACLs on namespace
+  public static HAContext getHAServerContext(Configuration conf) throws Exception {
+    HAContext serverContext = getHAContext(conf);
+    serverContext.checkAndSetACLs();
+    return serverContext;
+  }
+
+  @VisibleForTesting
+  public static synchronized void clearServerContext() {
+    if (serverHAContext != null) {
+      serverHAContext.getCuratorFramework().close();
+      serverHAContext = null;
+    }
+  }
+
+  public void startCuratorFramework() {
+    if (curatorFramework.getState() != CuratorFrameworkState.STARTED) {
+      curatorFramework.start();
+    }
+  }
+
+  public CuratorFramework getCuratorFramework() {
+    return this.curatorFramework;
+  }
+
+  public String getZookeeperQuorum() {
+    return zookeeperQuorum;
+  }
+
+  public static boolean isHaEnabled(Configuration conf) {
+    return conf.getBoolean(ServerConfig.SENTRY_HA_ENABLED, ServerConfig.SENTRY_HA_ENABLED_DEFAULT);
+  }
+
+  public String getNamespace() {
+    return namespace;
+  }
+
+  public RetryPolicy getRetryPolicy() {
+    return retryPolicy;
+  }
+
+  private void validateConf() {
+    Preconditions.checkNotNull(zookeeperQuorum, "Zookeeper Quorum should not be null.");
+    Preconditions.checkNotNull(namespace, "Zookeeper namespace should not be null.");
+  }
+
+  protected String getServicePrincipal(Configuration conf, String confProperty)
+      throws IOException {
+    String principal = conf.get(confProperty);
+    Preconditions.checkNotNull(principal);
+    Preconditions.checkArgument(principal.length() != 0, "Server principal is not right.");
+    return principal.split("[/@]")[0];
+  }
+
+  private void checkAndSetACLs() throws Exception {
+    if (zkSecure && !aclChecked) {
+      // If znodes were previously created without security enabled, and now it is, we need to go through all existing znodes
+      // and set the ACLs for them. This is done just once at the startup
+      // We can't get the namespace znode through curator; have to go through zk client
+      startCuratorFramework();
+      String newNamespace = "/" + curatorFramework.getNamespace();
+      if (curatorFramework.getZookeeperClient().getZooKeeper().exists(newNamespace, null) != null) {
+        List<ACL> acls = curatorFramework.getZookeeperClient().getZooKeeper().getACL(newNamespace, new Stat());
+        if (acls.isEmpty() || !acls.get(0).getId().getScheme().equals("sasl")) {
+          LOGGER.info("'sasl' ACLs not set; setting...");
+          List<String> children = curatorFramework.getZookeeperClient().getZooKeeper().getChildren(newNamespace, null);
+          for (String child : children) {
+            checkAndSetACLs("/" + child);
+          }
+          curatorFramework.getZookeeperClient().getZooKeeper().setACL(newNamespace, saslACL, -1);
+        }
+      }
+      aclChecked = true;
+
+    }
+  }
+
+  private void checkAndSetACLs(String path) throws Exception {
+      LOGGER.info("Setting acls on " + path);
+      List<String> children = curatorFramework.getChildren().forPath(path);
+      for (String child : children) {
+        checkAndSetACLs(path + "/" + child);
+      }
+      curatorFramework.setACL().withACL(saslACL).forPath(path);
+  }
+
+  // This gets ignored during most tests, see ZKXTestCaseWithSecurity#setupZKServer()
+  private void setJaasConfiguration(Configuration conf) throws IOException {
+    if ("false".equalsIgnoreCase(conf.get(
+          ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_TICKET_CACHE,
+          ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_TICKET_CACHE_DEFAULT))) {
+      String keytabFile = conf.get(ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_KEYTAB);
+      Preconditions.checkArgument(keytabFile.length() != 0, "Keytab File is not right.");
+      String principal = conf.get(ServerConfig.SERVER_HA_ZOOKEEPER_CLIENT_PRINCIPAL);
+      principal = SecurityUtil.getServerPrincipal(principal,
+        conf.get(ServerConfig.RPC_ADDRESS, ServerConfig.RPC_ADDRESS_DEFAULT));
+      Preconditions.checkArgument(principal.length() != 0, "Kerberos principal is not right.");
+
+      // This is equivalent to writing a jaas.conf file and setting the system property, "java.security.auth.login.config", to
+      // point to it (but this way we don't have to write a file, and it works better for the tests)
+      JaasConfiguration.addEntryForKeytab(SENTRY_ZK_JAAS_NAME, principal, keytabFile);
+    } else {
+      // Create jaas conf for ticket cache
+      JaasConfiguration.addEntryForTicketCache(SENTRY_ZK_JAAS_NAME);
+    }
+    javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
+  }
+
+  public class SASLOwnerACLProvider implements ACLProvider {
+    @Override
+    public List<ACL> getDefaultAcl() {
+        return saslACL;
+    }
+
+    @Override
+    public List<ACL> getAclForPath(String path) {
+        return saslACL;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/4767ec38/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java b/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java
new file mode 100644
index 0000000..a79ce5f
--- /dev/null
+++ b/sentry-service/sentry-service-common/src/main/java/org/apache/sentry/service/thrift/JaasConfiguration.java
@@ -0,0 +1,133 @@
+/**
+ * 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.sentry.service.thrift;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+/**
+ * Creates a programmatic version of a jaas.conf file.  This can be used instead of writing a jaas.conf file and setting
+ * the system property, "java.security.auth.login.config", to point to that file.  It is meant to be used for connecting to
+ * ZooKeeper.
+ * <p>
+ * example usage:
+ * JaasConfiguration.addEntry("Client", principal, keytabFile);
+ * javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
+ */
+public final class JaasConfiguration extends Configuration {
+  private static Map<String, AppConfigurationEntry> entries = new HashMap<String, AppConfigurationEntry>();
+  private static JaasConfiguration me = null;
+  private static final String krb5LoginModuleName;
+
+  static  {
+    if (System.getProperty("java.vendor").contains("IBM")) {
+      krb5LoginModuleName = "com.ibm.security.auth.module.Krb5LoginModule";
+    }
+    else {
+      krb5LoginModuleName = "com.sun.security.auth.module.Krb5LoginModule";
+    }
+  }
+
+  private JaasConfiguration() {
+    // don't need to do anything here but we want to make it private
+  }
+
+  /**
+   * Return the singleton.  You'd typically use it only to do this:
+   * <p>
+   * javax.security.auth.login.Configuration.setConfiguration(JaasConfiguration.getInstance());
+   *
+   * @return
+   */
+  public static Configuration getInstance() {
+    if (me == null) {
+      me = new JaasConfiguration();
+    }
+    return me;
+  }
+
+  /**
+   * Add an entry to the jaas configuration with the passed in name, principal, and keytab.  The other necessary options will be
+   * set for you.
+   *
+   * @param name The name of the entry (e.g. "Client")
+   * @param principal The principal of the user
+   * @param keytab The location of the keytab
+   */
+  public static void addEntryForKeytab(String name, String principal, String keytab) {
+    Map<String, String> options = new HashMap<String, String>();
+    options.put("keyTab", keytab);
+    options.put("principal", principal);
+    options.put("useKeyTab", "true");
+    options.put("storeKey", "true");
+    options.put("useTicketCache", "false");
+    AppConfigurationEntry entry = new AppConfigurationEntry(krb5LoginModuleName,
+        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+    entries.put(name, entry);
+  }
+
+  /**
+   * Add an entry to the jaas configuration with the passed in name. The other
+   * necessary options will be set for you.
+   *
+   * @param name The name of the entry (e.g. "Client")
+   */
+  public static void addEntryForTicketCache(String sectionName) {
+    Map<String, String> options = new HashMap<String, String>();
+    options.put("useKeyTab", "false");
+    options.put("storeKey", "false");
+    options.put("useTicketCache", "true");
+    AppConfigurationEntry entry = new AppConfigurationEntry(krb5LoginModuleName,
+        AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+    entries.put(sectionName, entry);
+  }
+
+  /**
+   * Removes the specified entry.
+   *
+   * @param name  The name of the entry to remove
+   */
+  public static void removeEntry(String name) {
+    entries.remove(name);
+  }
+
+  /**
+   * Clears all entries.
+   */
+  public static void clearEntries() {
+    entries.clear();
+  }
+
+  /**
+   * Returns the entries map.
+   *
+   * @return the entries map
+   */
+  public static Map<String, AppConfigurationEntry> getEntries() {
+    return entries;
+  }
+
+  @Override
+  public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+    return new AppConfigurationEntry[]{entries.get(name)};
+  }
+}
+


Mime
View raw message