Hi Colin and Team,

We are implementing Sentry-ha redesign in the branch *redesign-sentry-ha*,
do you think this commit need also go into that branch. From now on, we
might want to check in ha fixes in both trunk and branch.

Thanks,
Anne
On Jun 21, 2016 10:27 PM, <[email protected]> wrote:

> 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 <[email protected]>
> Authored: Wed Jun 22 14:11:57 2016 +0800
> Committer: Colin Ma <[email protected]>
> 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)};
> +  }
> +}
> +
>
>

Reply via email to