You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2017/04/19 03:41:25 UTC
[1/2] directory-kerby git commit: Revert "Backup the backends to
backup-for-backends branch."
Repository: directory-kerby
Updated Branches:
refs/heads/trunk 12e1811a1 -> 43ab5afe0
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNodeHelper.java
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNodeHelper.java b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNodeHelper.java
new file mode 100644
index 0000000..a59ede8
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNodeHelper.java
@@ -0,0 +1,191 @@
+/**
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooKeeper;
+
+import java.util.List;
+
+public class IdentityZNodeHelper {
+
+ private static final String IDENTITIES_ZNODE_NAME = "identities";
+ private static final String PRINCIPAL_NAME_ZNODE_NAME = "principalName";
+ private static final String KEY_VERSION_ZNODE_NAME = "keyVersion";
+ private static final String KDC_FLAGS_ZNODE_NAME = "kdcFlags";
+ private static final String DISABLED_ZNODE_NAME = "disabled";
+ private static final String LOCKED_ZNODE_NAME = "locked";
+ private static final String EXPIRE_TIME_ZNODE_NAME = "expireTime";
+ private static final String CREATED_TIME_ZNODE_NAME = "createdTime";
+ private static final String KEYS_ZNODE_NAME = "keys";
+ private static final String KEY_TYPE_ZNODE_NAME = "keyType";
+ private static final String KEY_ZNODE_NAME = "keyData";
+ private static final String ENCRYPTION_KEY_NO_ZNODE_NAME = "keyNo";
+ private static String baseZNode = "/kerby";
+
+ /**
+ * Get base znode.
+ * @return Base
+ */
+ public static String getBaseZNode() {
+ return baseZNode;
+ }
+
+ /**
+ * Get identities znode.
+ * @return Identities.
+ */
+ public static String getIdentitiesZNode() {
+ return ZKUtil.joinZNode(getBaseZNode(), IDENTITIES_ZNODE_NAME);
+ }
+
+ /**
+ * Get identity znode.
+ * @param principalName Principal name
+ * @return Identity
+ */
+ public static String getIndentityZNode(String principalName) {
+ return ZKUtil.joinZNode(getIdentitiesZNode(), principalName);
+ }
+
+ /**
+ * Get principal name znode.
+ * @param principalName Principal name.
+ * @return Principal name
+ */
+ public static String getPrincipalNameZnode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), PRINCIPAL_NAME_ZNODE_NAME);
+ }
+
+ /**
+ * Get key version znode.
+ * @param principalName Principal name.
+ * @return Key version
+ */
+ public static String getKeyVersionZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), KEY_VERSION_ZNODE_NAME);
+ }
+
+ /**
+ * Get kdc flags znode.
+ * @param principalName Principal name.
+ * @return Kdc flags
+ */
+ public static String getKdcFlagsZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), KDC_FLAGS_ZNODE_NAME);
+ }
+
+ /**
+ * Get disabled znode.
+ * @param principalName Principal name.
+ * @return Whether this principal's account is disabled.
+ */
+ public static String getDisabledZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), DISABLED_ZNODE_NAME);
+ }
+
+ /**
+ * Get locked znode.
+ * @param principalName Principal name.
+ * @return Whether principal's account is locked
+ */
+ public static String getLockedZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), LOCKED_ZNODE_NAME);
+ }
+
+ /**
+ * Get expire time znode.
+ * @param principalName Principal name.
+ * @return Expired time.
+ */
+ public static String getExpireTimeZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), EXPIRE_TIME_ZNODE_NAME);
+ }
+
+ /**
+ * Get created time znode.
+ * @param principalName Principal name.
+ * @return Created time.
+ */
+ public static String getCreatedTimeZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), CREATED_TIME_ZNODE_NAME);
+ }
+
+ /**
+ * Get keys znode.
+ * @param principalName Principal name.
+ * @return Key
+ */
+ public static String getKeysZNode(String principalName) {
+ return ZKUtil.joinZNode(getIndentityZNode(principalName), KEYS_ZNODE_NAME);
+ }
+
+ /**
+ * Get key type znode.
+ * @param principalName Principal name.
+ * @param type Key type.
+ * @return Key type.
+ */
+ public static String getKeyTypeZNode(String principalName, String type) {
+ return ZKUtil.joinZNode(getKeysZNode(principalName), type);
+ }
+
+ /**
+ * Get encryption key type znode.
+ * @param principalName Principal name.
+ * @param type Encryption type.
+ * @return Encryption key type
+ */
+ public static String getEncryptionKeyTypeZNode(String principalName, String type) {
+ return ZKUtil.joinZNode(getKeyTypeZNode(principalName, type), KEY_TYPE_ZNODE_NAME);
+ }
+
+ /**
+ * Get encryption key znode.
+ * @param principalName Principal Name.
+ * @param type Encryption type.
+ * @return Encryption key
+ */
+ public static String getEncryptionKeyZNode(String principalName, String type) {
+ return ZKUtil.joinZNode(getKeyTypeZNode(principalName, type), KEY_ZNODE_NAME);
+ }
+
+ /**
+ * Get encryption key kvno znode.
+ * @param principalName Principal name.
+ * @param type Key type.
+ * @return Encryption key
+ */
+ public static String getEncryptionKeyNoZNode(String principalName, String type) {
+ return ZKUtil.joinZNode(getKeyTypeZNode(principalName, type), ENCRYPTION_KEY_NO_ZNODE_NAME);
+ }
+
+ /**
+ * Get identity names.
+ *
+ * @throws org.apache.zookeeper.KeeperException e
+ * @param zk The zookeeper
+ * @return The list of principal names.
+ */
+ public static List<String> getIdentityNames(ZooKeeper zk) throws KeeperException {
+ List<String> identityNames = ZKUtil.listChildrenNoWatch(zk, getIdentitiesZNode());
+ return identityNames;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKConfKey.java
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKConfKey.java b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKConfKey.java
new file mode 100644
index 0000000..b82b1a0
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKConfKey.java
@@ -0,0 +1,52 @@
+/**
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.kerby.config.ConfigKey;
+
+/**
+ * Define all the ZK backend related configuration items with default values.
+ */
+public enum ZKConfKey implements ConfigKey {
+ EMBEDDED_ZK(true),
+ ZK_HOST("127.0.0.1"),
+ ZK_PORT(2180),
+ DATA_DIR("/tmp/kerby/zookeeper/data");
+
+ private Object defaultValue;
+
+ ZKConfKey() {
+ this.defaultValue = null;
+ }
+
+ ZKConfKey(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public String getPropertyKey() {
+ return name().toLowerCase();
+ }
+
+ @Override
+ public Object getDefaultValue() {
+ return this.defaultValue;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKUtil.java
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKUtil.java b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKUtil.java
new file mode 100644
index 0000000..8ebe100
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZKUtil.java
@@ -0,0 +1,229 @@
+/**
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooDefs;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Stat;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * utility class for ZooKeeper
+ */
+public class ZKUtil {
+ public static final char ZNODE_PATH_SEPARATOR = '/';
+ private static final Logger LOG = LoggerFactory.getLogger(ZKUtil.class);
+
+ public static String joinZNode(String prefix, String suffix) {
+ return prefix + ZNODE_PATH_SEPARATOR + suffix;
+ }
+
+ /**
+ * Check if the specified node exists. Sets no watches.
+ * @throws org.apache.zookeeper.KeeperException e
+ * @param zk Zookeeper.
+ * @param node Node.
+ * @return The version.
+ */
+ public static int checkExists(ZooKeeper zk, String node)
+ throws KeeperException {
+ try {
+ Stat s = zk.exists(node, null);
+ return s != null ? s.getVersion() : -1;
+ } catch (KeeperException e) {
+ return -1;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return -1;
+ }
+ }
+
+ /**
+ * Sets the data of the existing znode to be the specified data.
+ * @throws org.apache.zookeeper.KeeperException e
+ * @param zk Zookeeper
+ * @param node Node
+ * @param data Data
+ * @return Whether the data is set or not.
+ */
+ public static boolean setData(ZooKeeper zk, String node, byte[] data)
+ throws KeeperException {
+ try {
+ return zk.setData(node, data, -1) != null;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
+
+ /**
+ * Set data into node creating node if it doesn't yet exist.
+ * Does not set watch.
+ * @param zk Zookeeper.
+ * @param node Node.
+ * @param data Data.
+ * @throws KeeperException e
+ */
+ public static void createSetData(final ZooKeeper zk, final String node,
+ final byte[] data)
+ throws KeeperException {
+ if (checkExists(zk, node) == -1) {
+ ZKUtil.createWithParents(zk, node, data);
+ } else {
+ ZKUtil.setData(zk, node, data);
+ }
+ }
+
+ /**
+ * Creates the specified node and all parent nodes required for it to exist.
+ * @param zk The zookeeper
+ * @param node The znode
+ * @throws org.apache.zookeeper.KeeperException e
+ */
+ public static void createWithParents(ZooKeeper zk, String node)
+ throws KeeperException {
+ createWithParents(zk, node, new byte[0]);
+ }
+
+ /**
+ * Creates the specified node and all parent nodes required for it to exist. The creation of
+ * parent znodes is not atomic with the leafe znode creation but the data is written atomically
+ * when the leaf node is created.
+ * @throws org.apache.zookeeper.KeeperException e
+ * @param zk zookeeper.
+ * @param node node
+ * @param data data
+ */
+ public static void createWithParents(ZooKeeper zk, String node, byte[] data)
+ throws KeeperException {
+ try {
+ if (node == null) {
+ return;
+ }
+ zk.create(node, data, createACL(zk, node),
+ CreateMode.PERSISTENT);
+ } catch (KeeperException.NodeExistsException nee) {
+ return;
+ } catch (KeeperException.NoNodeException nne) {
+ createWithParents(zk, getParent(node));
+ createWithParents(zk, node, data);
+ } catch (InterruptedException ie) {
+ LOG.warn("Fail to create node: " + node, ie);
+ }
+ }
+
+ /**
+ * Returns the ACL list
+ * @param zk zookeeper
+ * @param node node
+ * @return The acl created.
+ */
+ private static ArrayList<ACL> createACL(ZooKeeper zk, String node) { //NOPMD
+ return ZooDefs.Ids.OPEN_ACL_UNSAFE; //TODO
+ }
+
+ /**
+ * Returns the full path of the immediate parent of the specified node.
+ * null if passed the root node or an invalid node
+ * @param node The znode
+ * @return index
+ */
+ public static String getParent(String node) {
+ int idx = node.lastIndexOf(ZNODE_PATH_SEPARATOR);
+ return idx <= 0 ? null : node.substring(0, idx);
+ }
+
+ /**
+ * Get znode data. Does not set a watcher.
+ * @param zk The zookeeper
+ * @param node The znode
+ * @throws org.apache.zookeeper.KeeperException e
+ * @throws java.lang.InterruptedException e
+ * @return Data of the node
+ */
+ public static byte[] getData(ZooKeeper zk, String node)
+ throws KeeperException, InterruptedException {
+ try {
+ byte[] data = zk.getData(node, false, null);
+ return data;
+ } catch (KeeperException.NoNodeException e) {
+ LOG.debug("Unable to get data of znode " + node + " because node does not exist");
+ return null;
+ } catch (KeeperException e) {
+ LOG.warn("Unable to get data of znode " + node, e);
+ return null;
+ }
+ }
+
+ /**
+ * Lists the children of the specified node without setting any watches.
+ * null if parent does not exist
+ * @param zk The zookeeper.
+ * @param node The znode
+ * @throws org.apache.zookeeper.KeeperException e
+ * @return children
+ */
+ public static List<String> listChildrenNoWatch(ZooKeeper zk, String node)
+ throws KeeperException {
+ List<String> children = null;
+ try {
+ // List the children without watching
+ children = zk.getChildren(node, null);
+ } catch (KeeperException.NoNodeException nne) {
+ return null;
+ } catch (InterruptedException ie) {
+ LOG.warn("Fail to list children of node: " + node, ie);
+ }
+ return children;
+ }
+
+ /**
+ * Delete the specified node and all of it's children.
+ * If the node does not exist, just returns.
+ * Sets no watches. Throws all exceptions besides dealing with deletion of
+ * children.
+ * @throws KeeperException e
+ * @param zk The zookeeper.
+ * @param node The node to be deleted.
+ */
+ public static void deleteNodeRecursively(ZooKeeper zk, String node) throws KeeperException {
+ List<String> children = ZKUtil.listChildrenNoWatch(zk, node);
+ if (children == null) {
+ return;
+ }
+ if (!children.isEmpty()) {
+ for (String child : children) {
+ deleteNodeRecursively(zk, joinZNode(node, child));
+ }
+ }
+ try {
+ zk.delete(node, -1);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZookeeperIdentityBackend.java
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZookeeperIdentityBackend.java b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZookeeperIdentityBackend.java
new file mode 100644
index 0000000..0436e66
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/ZookeeperIdentityBackend.java
@@ -0,0 +1,317 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.kerby.config.Config;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.AbstractIdentityBackend;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * A Zookeeper based backend implementation. Currently it uses an embedded
+ * Zookeeper. In follow up it will be enhanced to support standalone Zookeeper
+ * cluster for replication and reliability.
+ */
+public class ZookeeperIdentityBackend extends AbstractIdentityBackend {
+ private static Thread zookeeperThread;
+ private final ZooKeeperServerMain zooKeeperServer = new ZooKeeperServerMain();
+ private String zkHost;
+ private int zkPort;
+ private File dataDir;
+ private ZooKeeper zooKeeper;
+ private static final Logger LOG = LoggerFactory.getLogger(ZookeeperIdentityBackend.class);
+
+ public ZookeeperIdentityBackend() {
+
+ }
+
+ /**
+ * Constructing an instance using specified config that contains anything
+ * to be used to init the Zookeeper backend.
+ * @param config The configuration for zookeeper identity backend.
+ */
+ public ZookeeperIdentityBackend(Config config) {
+ setConfig(config);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doInitialize() throws KrbException {
+ LOG.info("Initializing the Zookeeper identity backend.");
+ init();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStop() throws KrbException {
+ try {
+ zooKeeper.close();
+ } catch (InterruptedException e) {
+ LOG.error("Closing zookeeper interrupted." + e);
+ }
+ LOG.info("Zookeeper session closed.");
+ }
+
+ /**
+ * Init Zookeeper Server and connection service, used to initialize the backend.
+ */
+ private void init() throws KrbException {
+ zkHost = getConfig().getString(ZKConfKey.ZK_HOST, true);
+ zkPort = getConfig().getInt(ZKConfKey.ZK_PORT, true);
+
+ String dataDirString = getConfig().getString(ZKConfKey.DATA_DIR, true);
+ if (dataDirString == null || dataDirString.isEmpty()) {
+ File zooKeeperDir = new File(getBackendConfig().getConfDir(), "zookeeper");
+ dataDir = new File(zooKeeperDir, "data");
+ } else {
+ dataDir = new File(dataDirString);
+ }
+
+ if (!dataDir.exists() && !dataDir.mkdirs()) {
+ throw new KrbException("could not create data file dir " + dataDir);
+ }
+
+ LOG.info("Data dir: " + dataDir);
+
+ if (getConfig().getBoolean(ZKConfKey.EMBEDDED_ZK, true)) {
+ startEmbeddedZookeeper();
+ }
+ connectZK();
+ }
+
+ /**
+ * Prepare connection to Zookeeper server.
+ */
+ private void connectZK() throws KrbException {
+ try {
+ String serverStr = zkHost + ":" + zkPort;
+ zooKeeper = new ZooKeeper(serverStr, 10000, new MyWatcher());
+ while (true) {
+ if (!zooKeeper.getState().isConnected()) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ LOG.error("Some thread has interrupted the current thread" + e);
+ }
+ } else {
+ LOG.info("Success connect to zookeeper server.");
+ break;
+ }
+ }
+
+ } catch (IOException e) {
+ LOG.error("Error occurred while connecting to zookeeper.");
+ throw new KrbException("Failed to prepare Zookeeper connection");
+ }
+ }
+
+ /**
+ * Start the Zookeeper server
+ */
+ private void startEmbeddedZookeeper() throws KrbException {
+ Properties startupProperties = new Properties();
+ startupProperties.put("dataDir", dataDir.getAbsolutePath());
+ startupProperties.put("clientPort", zkPort);
+
+ QuorumPeerConfig quorumConfiguration = new QuorumPeerConfig();
+ try {
+ quorumConfiguration.parseProperties(startupProperties);
+ } catch (Exception e) {
+ throw new KrbException("Loading quorum configuraiton failed", e);
+ }
+
+ final ServerConfig configuration = new ServerConfig();
+ configuration.readFrom(quorumConfiguration);
+
+ if (zookeeperThread == null) {
+ zookeeperThread = new Thread() {
+ public void run() {
+ try {
+ zooKeeperServer.runFromConfig(configuration);
+ } catch (IOException e) {
+ LOG.warn(e.getMessage());
+ }
+ }
+ };
+ zookeeperThread.setDaemon(true);
+ zookeeperThread.start();
+ }
+ LOG.info("Embedded Zookeeper started.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doGetIdentity(String principalName) throws KrbException {
+ principalName = replaceSlash(principalName);
+ IdentityZNode identityZNode = new IdentityZNode(zooKeeper, principalName);
+ KrbIdentity krb = new KrbIdentity(principalName);
+ try {
+ if (!identityZNode.exist()) {
+ return null;
+ }
+ krb.setPrincipal(identityZNode.getPrincipalName());
+ krb.setCreatedTime(identityZNode.getCreatedTime());
+ krb.setDisabled(identityZNode.getDisabled());
+ krb.setExpireTime(identityZNode.getExpireTime());
+ krb.setKdcFlags(identityZNode.getKdcFlags());
+ krb.addKeys(identityZNode.getKeys());
+ krb.setKeyVersion(identityZNode.getKeyVersion());
+ krb.setLocked(identityZNode.getLocked());
+ } catch (KeeperException e) {
+ throw new KrbException("Fail to get identity from zookeeper", e);
+ }
+
+ return krb;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doAddIdentity(KrbIdentity identity) throws KrbException {
+ try {
+ setIdentity(identity);
+ } catch (Exception e) {
+ throw new KrbException("Fail to add identity to zookeeper", e);
+ }
+ return doGetIdentity(identity.getPrincipalName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doUpdateIdentity(KrbIdentity identity) throws KrbException {
+ try {
+ setIdentity(identity);
+ } catch (Exception e) {
+ throw new KrbException("Fail to update identity in zookeeper", e);
+ }
+ return doGetIdentity(identity.getPrincipalName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doDeleteIdentity(String principalName) throws KrbException {
+ principalName = replaceSlash(principalName);
+ IdentityZNode identityZNode = new IdentityZNode(zooKeeper, principalName);
+ try {
+ identityZNode.deleteIdentity();
+ } catch (KeeperException e) {
+ throw new KrbException("Fail to delete identity in zookeeper", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Iterable<String> doGetIdentities() throws KrbException {
+ List<String> identityNames;
+
+ try {
+ // The identities getting from zookeeper is unordered
+ identityNames = IdentityZNodeHelper.getIdentityNames(zooKeeper);
+ } catch (KeeperException e) {
+ throw new KrbException("Fail to get identities from zookeeper", e);
+ }
+
+ if (identityNames == null || identityNames.isEmpty()) {
+ return null;
+ }
+
+ List<String> newIdentities = new ArrayList<>(identityNames.size());
+ for (String name : identityNames) {
+ if (name.contains("\\")) {
+ name = name.replace("\\", "/");
+ }
+ newIdentities.add(name);
+ }
+ Collections.sort(newIdentities);
+ return newIdentities;
+ }
+
+ /**
+ * Set the identity to add or update an indentity in the backend.
+ * @param identity . The identity to update
+ * @throws org.apache.zookeeper.KeeperException
+ */
+ private void setIdentity(KrbIdentity identity) throws KeeperException, IOException {
+ String principalName = identity.getPrincipalName();
+ principalName = replaceSlash(principalName);
+ IdentityZNode identityZNode = new IdentityZNode(zooKeeper, principalName);
+ identityZNode.setPrincipalName(identity.getPrincipalName());
+ identityZNode.setCreatedTime(identity.getCreatedTime());
+ identityZNode.setDisabled(identity.isDisabled());
+ identityZNode.setExpireTime(identity.getExpireTime());
+ identityZNode.setKdcFlags(identity.getKdcFlags());
+ identityZNode.setKeys(identity.getKeys());
+ identityZNode.setKeyVersion(identity.getKeyVersion());
+ identityZNode.setLocked(identity.isLocked());
+ }
+
+ /**
+ * Use "\\" to replace "/" in a String object.
+ * @param name . The the name string to convert
+ * @return
+ */
+ private String replaceSlash(String name) {
+ if (name.contains("/")) {
+ name = name.replace("/", "\\");
+ }
+ return name;
+ }
+
+ class MyWatcher implements Watcher {
+
+ /**
+ * This will watch all the kdb update event so that it's timely synced.
+ * @param event The kdb update event ot watch.
+ */
+ public void process(WatchedEvent event) {
+// System.out.println("I got an event: " + event.getPath());
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/ZookeeperBackendTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/ZookeeperBackendTest.java b/kerby-backend/zookeeper-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/ZookeeperBackendTest.java
new file mode 100644
index 0000000..8f34123
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/ZookeeperBackendTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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.kerby.kerberos.kerb.identity.backend;
+
+import org.apache.kerby.config.Conf;
+import org.apache.kerby.kerberos.kdc.identitybackend.ZKConfKey;
+import org.apache.kerby.kerberos.kdc.identitybackend.ZookeeperIdentityBackend;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import java.io.File;
+
+/**
+ * Zookeeper backend test
+ */
+public class ZookeeperBackendTest extends BackendTestBase {
+ private static File instanceDir;
+ private static File dataDir;
+
+ @BeforeClass
+ public static void setup() throws KrbException {
+ Conf config = new Conf();
+ File testdir = new File(System.getProperty("test.dir", "target"));
+ instanceDir = new File(testdir, "zookeeper");
+ instanceDir.mkdirs();
+ dataDir = new File(instanceDir, "data");
+ dataDir.mkdirs();
+ config.setString(ZKConfKey.DATA_DIR.getPropertyKey(), dataDir.getAbsolutePath());
+
+ backend = new ZookeeperIdentityBackend(config);
+ backend.initialize();
+ backend.start();
+ }
+
+ @AfterClass
+ public static void tearDown() throws KrbException {
+ if (dataDir.exists()) {
+ dataDir.delete();
+ }
+ if (instanceDir.exists()) {
+ instanceDir.delete();
+ }
+ if (backend != null) {
+ backend.stop();
+ backend.release();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-dist/README.md
----------------------------------------------------------------------
diff --git a/kerby-dist/README.md b/kerby-dist/README.md
index a80a37b..8764ae4 100644
--- a/kerby-dist/README.md
+++ b/kerby-dist/README.md
@@ -78,6 +78,12 @@ An example of json backend backend.conf:
kdc_identity_backend = org.apache.kerby.kerberos.kdc.identitybackend.JsonIdentityBackend
backend.json.dir = /tmp/kerby/jsonbackend
```
+An example of zookeeper backend backend.conf:
+```
+kdc_identity_backend = org.apache.kerby.kerberos.kdc.identitybackend.ZookeeperIdentityBackend
+data_dir = /tmp/kerby/zookeeper/data
+data_log_dir = /tmp/kerby/zookeeper/datalog
+```
An example of krb5.conf:
```
[libdefaults]
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-dist/kdc-dist/conf/backend.conf
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/conf/backend.conf b/kerby-dist/kdc-dist/conf/backend.conf
index 35dc8e3..2ead268 100644
--- a/kerby-dist/kdc-dist/conf/backend.conf
+++ b/kerby-dist/kdc-dist/conf/backend.conf
@@ -18,3 +18,7 @@
kdc_identity_backend = org.apache.kerby.kerberos.kdc.identitybackend.JsonIdentityBackend
backend.json.dir = /tmp/kerby/jsonbackend
+embedded_zk = false
+zk_host = 127.0.0.1
+zk_port = 2181
+data_dir = /tmp/zookeeper/data
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-dist/kdc-dist/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/pom.xml b/kerby-dist/kdc-dist/pom.xml
index c70f5c6..da3a2e1 100644
--- a/kerby-dist/kdc-dist/pom.xml
+++ b/kerby-dist/kdc-dist/pom.xml
@@ -96,6 +96,17 @@
<version>${project.version}</version>
</dependency>
+ <!-- For Zookeeper backend -->
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>zookeeper-backend</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ <version>3.4.6</version>
+ </dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-kdc-test/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/pom.xml b/kerby-kdc-test/pom.xml
index 160a2c6..4ec0589 100644
--- a/kerby-kdc-test/pom.xml
+++ b/kerby-kdc-test/pom.xml
@@ -66,6 +66,16 @@
</dependency>
<dependency>
<groupId>org.apache.kerby</groupId>
+ <artifactId>zookeeper-backend</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>ldap-backend</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
<artifactId>token-provider</artifactId>
<version>${project.version}</version>
</dependency>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-kdc-test/src/main/resources/kdc.ldiff
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/src/main/resources/kdc.ldiff b/kerby-kdc-test/src/main/resources/kdc.ldiff
new file mode 100644
index 0000000..bc989c3
--- /dev/null
+++ b/kerby-kdc-test/src/main/resources/kdc.ldiff
@@ -0,0 +1,46 @@
+# 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.
+dn: ou=users,dc=${0},dc=${1}
+objectClass: organizationalUnit
+objectClass: top
+ou: users
+
+dn: uid=krbtgt,ou=users,dc=${0},dc=${1}
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: KDC Service
+sn: Service
+uid: krbtgt
+userPassword: secret
+krb5PrincipalName: krbtgt/${2}.${3}@${2}.${3}
+krb5KeyVersionNumber: 0
+
+dn: uid=ldap,ou=users,dc=${0},dc=${1}
+objectClass: top
+objectClass: person
+objectClass: inetOrgPerson
+objectClass: krb5principal
+objectClass: krb5kdcentry
+cn: LDAP
+sn: Service
+uid: ldap
+userPassword: secret
+krb5PrincipalName: ldap/${4}@${2}.${3}
+krb5KeyVersionNumber: 0
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/AbstractLdapBackendKdcTest.java
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/AbstractLdapBackendKdcTest.java b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/AbstractLdapBackendKdcTest.java
new file mode 100644
index 0000000..7fe2f7a
--- /dev/null
+++ b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/AbstractLdapBackendKdcTest.java
@@ -0,0 +1,50 @@
+/**
+ * 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.kerby.kerberos.kdc;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.ldap.LdapServer;
+
+public class AbstractLdapBackendKdcTest extends KerbyKdcTest {
+
+ /** The used DirectoryService instance */
+ private static DirectoryService service;
+
+ /** The used LdapServer instance */
+ private static LdapServer ldapServer;
+
+ public static DirectoryService getService() {
+ return service;
+ }
+
+
+ public static void setService(DirectoryService service) {
+ AbstractLdapBackendKdcTest.service = service;
+ }
+
+
+ public static LdapServer getLdapServer() {
+ return ldapServer;
+ }
+
+ public static void setLdapServer(LdapServer ldapServer) {
+ AbstractLdapBackendKdcTest.ldapServer = ldapServer;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/JsonBackendKdcTest.java
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/JsonBackendKdcTest.java b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/JsonBackendKdcTest.java
new file mode 100644
index 0000000..9247e3e
--- /dev/null
+++ b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/JsonBackendKdcTest.java
@@ -0,0 +1,60 @@
+/**
+ * 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.kerby.kerberos.kdc;
+
+import org.apache.kerby.kerberos.kdc.identitybackend.JsonIdentityBackend;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcConfigKey;
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import java.io.File;
+
+public class JsonBackendKdcTest extends KerbyKdcTest {
+ private static File jsonBackendFile;
+
+ @Override
+ protected void prepareKdc() throws KrbException {
+
+ File testDir = new File(System.getProperty("test.dir", "target"));
+ jsonBackendFile = new File(testDir, "json-backend-file");
+ String jsonBackendFileString = jsonBackendFile.getAbsolutePath();
+
+ BackendConfig backendConfig = getKdcServer().getBackendConfig();
+ backendConfig.setString(
+ JsonIdentityBackend.JSON_IDENTITY_BACKEND_DIR, jsonBackendFileString);
+ backendConfig.setString(KdcConfigKey.KDC_IDENTITY_BACKEND,
+ "org.apache.kerby.kerberos.kdc.identitybackend.JsonIdentityBackend");
+ super.prepareKdc();
+ }
+
+ @Test
+ public void testKdc() throws Exception {
+ performKdcTest();
+ }
+
+ @AfterClass
+ public static void rmJsonBackendFile() {
+ if (jsonBackendFile.exists()) {
+ jsonBackendFile.delete();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/LdapBackendKdcTest.java
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/LdapBackendKdcTest.java b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/LdapBackendKdcTest.java
new file mode 100644
index 0000000..d3f20ae
--- /dev/null
+++ b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/LdapBackendKdcTest.java
@@ -0,0 +1,105 @@
+/**
+ * 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.kerby.kerberos.kdc;
+
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.apache.kerby.config.Conf;
+import org.apache.kerby.kerberos.kdc.identitybackend.LdapIdentityBackend;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcConfigKey;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(FrameworkRunner.class)
+@CreateDS(name = "KerberosKRBProtocolTest-class",
+ partitions =
+ {
+ @CreatePartition(
+ name = "example",
+ suffix = "dc=example,dc=com")
+ })
+@CreateLdapServer(
+ transports =
+ {
+ @CreateTransport(protocol = "LDAP", address = "127.0.0.1")
+ })
+@ApplyLdifs(
+ {
+ "dn: dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: domain",
+ "dc: example",
+ "dn: ou=users,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: users"
+ }
+)
+public class LdapBackendKdcTest extends AbstractLdapBackendKdcTest {
+ private LdapIdentityBackend backend;
+ private static final String BASE_DN = "ou=users,dc=example,dc=com";
+ private static final String ADMIN_DN = "uid=admin,ou=system";
+ private static final String ADMIN_PW = "secret";
+
+ @Before
+ public void startUp() throws Exception {
+ Conf config = new Conf();
+ config.setString("host", "127.0.0.1");
+ config.setString("admin_dn", ADMIN_DN);
+ config.setString("admin_pw", ADMIN_PW);
+ config.setString("base_dn", BASE_DN);
+ config.setInt("port", getLdapServer().getPort());
+ this.backend = new LdapIdentityBackend(config);
+ backend.initialize();
+ backend.start();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ backend.stop();
+ backend.release();
+ }
+
+ @Override
+ protected void prepareKdc() throws KrbException {
+ BackendConfig backendConfig = getKdcServer().getBackendConfig();
+ backendConfig.setString("host", "localhost");
+ backendConfig.setString("admin_dn", ADMIN_DN);
+ backendConfig.setString("admin_pw", ADMIN_PW);
+ backendConfig.setString("base_dn", BASE_DN);
+ backendConfig.setInt("port", getLdapServer().getPort());
+ backendConfig.setString(KdcConfigKey.KDC_IDENTITY_BACKEND,
+ "org.apache.kerby.kerberos.kdc.identitybackend.LdapIdentityBackend");
+ super.prepareKdc();
+ }
+
+ @Test
+ public void testKdc() throws Exception {
+ performKdcTest();
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/ZookeeperBackendKdcTest.java
----------------------------------------------------------------------
diff --git a/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/ZookeeperBackendKdcTest.java b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/ZookeeperBackendKdcTest.java
new file mode 100644
index 0000000..f0634e7
--- /dev/null
+++ b/kerby-kdc-test/src/test/java/org/apache/kerby/kerberos/kdc/ZookeeperBackendKdcTest.java
@@ -0,0 +1,52 @@
+/**
+ * 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.kerby.kerberos.kdc;
+
+import org.apache.kerby.kerberos.kdc.identitybackend.ZKConfKey;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcConfigKey;
+import org.junit.Test;
+
+import java.io.File;
+
+public class ZookeeperBackendKdcTest extends KerbyKdcTest {
+
+ @Override
+ protected void prepareKdc() throws KrbException {
+ BackendConfig backendConfig = getKdcServer().getBackendConfig();
+
+ File testDir = getTestDir();
+ File instanceDir = new File(testDir, "zookeeper");
+ instanceDir.mkdirs();
+ File dataDir = new File(instanceDir, "data");
+ dataDir.mkdirs();
+ backendConfig.setString(ZKConfKey.DATA_DIR.getPropertyKey(), dataDir.getAbsolutePath());
+ backendConfig.setString(KdcConfigKey.KDC_IDENTITY_BACKEND,
+ "org.apache.kerby.kerberos.kdc.identitybackend.ZookeeperIdentityBackend");
+
+ super.prepareKdc();
+ }
+
+ @Test
+ public void testKdc() throws Exception {
+ performKdcTest();
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 30dfbc3..3834a42 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,7 @@
<bouncycastle.version>1.55</bouncycastle.version>
<commons-io.version>2.5</commons-io.version>
<gson.version>2.6.2</gson.version>
+ <ldap.api.version>1.0.0-RC2</ldap.api.version>
<log4j.version>1.2.17</log4j.version>
<junit.version>4.12</junit.version>
<nimbus.jose.version>3.10</nimbus.jose.version>
[2/2] directory-kerby git commit: Revert "Backup the backends to
backup-for-backends branch."
Posted by pl...@apache.org.
Revert "Backup the backends to backup-for-backends branch."
This reverts commit 12e1811a1be0b1d50813427ac20d582839ac420b.
Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/43ab5afe
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/43ab5afe
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/43ab5afe
Branch: refs/heads/trunk
Commit: 43ab5afe0ffb402a5c5e98a4fe2f516109ec602d
Parents: 12e1811
Author: plusplusjiajia <ji...@intel.com>
Authored: Wed Apr 19 11:48:33 2017 +0800
Committer: plusplusjiajia <ji...@intel.com>
Committed: Wed Apr 19 11:48:33 2017 +0800
----------------------------------------------------------------------
README.md | 10 +-
benchmark/pom.xml | 5 +
docs/1.0.0-rc1/1.0.0-RC1-release-note.md | 3 +
kerby-backend/ldap-backend/pom.xml | 98 ++++++
.../identitybackend/LdapIdentityBackend.java | 351 +++++++++++++++++++
.../identitybackend/LdapIdentityGetHelper.java | 145 ++++++++
.../AbstractLdapIdentityBackendTest.java | 84 +++++
.../DirectoryLdapIdentityBackendTest.java | 77 ++++
.../backend/LdapIdentityBackendTest.java | 75 ++++
kerby-backend/mavibot-backend/pom.xml | 69 ++++
.../org/apache/kerby/KrbIdentityComparator.java | 43 +++
.../org/apache/kerby/KrbIdentitySerializer.java | 180 ++++++++++
.../java/org/apache/kerby/MavibotBackend.java | 202 +++++++++++
.../apache/kerby/KrbIdentitySerializerTest.java | 106 ++++++
.../org/apache/kerby/MavibotBackendTest.java | 89 +++++
kerby-backend/pom.xml | 3 +
kerby-backend/zookeeper-backend/pom.xml | 61 ++++
.../kdc/identitybackend/IdentityZNode.java | 346 ++++++++++++++++++
.../identitybackend/IdentityZNodeHelper.java | 191 ++++++++++
.../kerberos/kdc/identitybackend/ZKConfKey.java | 52 +++
.../kerberos/kdc/identitybackend/ZKUtil.java | 229 ++++++++++++
.../ZookeeperIdentityBackend.java | 317 +++++++++++++++++
.../identity/backend/ZookeeperBackendTest.java | 66 ++++
kerby-dist/README.md | 6 +
kerby-dist/kdc-dist/conf/backend.conf | 4 +
kerby-dist/kdc-dist/pom.xml | 11 +
kerby-kdc-test/pom.xml | 10 +
kerby-kdc-test/src/main/resources/kdc.ldiff | 46 +++
.../kdc/AbstractLdapBackendKdcTest.java | 50 +++
.../kerby/kerberos/kdc/JsonBackendKdcTest.java | 60 ++++
.../kerby/kerberos/kdc/LdapBackendKdcTest.java | 105 ++++++
.../kerberos/kdc/ZookeeperBackendKdcTest.java | 52 +++
pom.xml | 1 +
33 files changed, 3146 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index cdc8946..118e61c 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Apache Kerby, as an [Apache Directory](http://directory.staging.apache.org/) sub
### The Initiatives/Goals
- Aims as a Java Kerberos binding, with rich and integrated facilities that integrate Kerberos, PKI and token (OAuth2) for both client and server sides.
- Provides client APIs at the Kerberos protocol level to interact with a KDC server through AS and TGS exchanges.
-- Provides a standalone KDC server that supports various identity backends including memory based, Json file based.
+- Provides a standalone KDC server that supports various identity backends including memory based, Json file based, LDAP based and even Zookeeper based.
- Provides an embedded KDC server that applications can easily integrate into products, unit tests or integration tests.
- Supports FAST/Preauthentication framework to allow popular and useful authentication mechanisms.
- Supports PKINIT mechanism to allow clients to request tickets using x509 certificate credentials.
@@ -91,6 +91,13 @@ A standalone KDC server that can integrate various identity backends including:
- It is default Identity Backend, and no cofiguration is needed. This backend is for no permanent storage requirements.
- JsonIdentityBackend.
- It implemented by Gson which is used to convert Java Objects into their JSON representation and convert a JSON string to an equivalent Java object. A json file will be created in "backend.json.dir". This backend is for small, easy, development and test environment.
+- ZookeeperIdentityBackend.
+ - Currently it uses an embedded Zookeeper. In follow up it will be enhanced to support standalone Zookeeper cluster for
+ replication and reliability. Zookeeper backend would be a good choice for high reliability, high performance and high scalability requirement and scenarios.
+- LdapIdentityBackend.
+ - The Ldap server can be standalone or embedded using ApacheDS server as the backend. It is used when there is exist ldap server.
+- MavibotBackend.
+ - A backend based on Apache Mavibot(an MVCC BTree library).
### Network Support
- Include UDP and TCP transport.
@@ -119,6 +126,7 @@ A standalone KDC server that can integrate various identity backends including:
- The core part is ensured to only depend on the JRE and SLF4J. Every external dependency is taken carefully and maintained separately.
- [Nimbus JOSE + JWT](http://connect2id.com/products/nimbus-jose-jwt), needed by token-provider and TokenPreauth mechanism.
- [Netty](http://netty.io/), needed by netty based KDC server.
+- [Zookeeper](https://zookeeper.apache.org/), needed by zookeeper identity backend.
### How to use library
The Apache Kerby is also available as a Maven dependency.
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/benchmark/pom.xml
----------------------------------------------------------------------
diff --git a/benchmark/pom.xml b/benchmark/pom.xml
index 1543aa7..1d5c0d5 100644
--- a/benchmark/pom.xml
+++ b/benchmark/pom.xml
@@ -73,6 +73,11 @@
<artifactId>json-backend</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>zookeeper-backend</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
<profiles>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/docs/1.0.0-rc1/1.0.0-RC1-release-note.md
----------------------------------------------------------------------
diff --git a/docs/1.0.0-rc1/1.0.0-RC1-release-note.md b/docs/1.0.0-rc1/1.0.0-RC1-release-note.md
index 8587510..c8603e6 100644
--- a/docs/1.0.0-rc1/1.0.0-RC1-release-note.md
+++ b/docs/1.0.0-rc1/1.0.0-RC1-release-note.md
@@ -33,6 +33,9 @@ In this release 236 JIRA issues were resolved and the following features are sup
3. Support for various identity backends:
- In-memory
- JSON
+ - LDAP
+ - Mavibot(MVCC BTree)
+ - Zookeeper
4. Embedded KDC server allows easy integration into products for unit tests or production deployment.
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/ldap-backend/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-backend/ldap-backend/pom.xml b/kerby-backend/ldap-backend/pom.xml
new file mode 100644
index 0000000..e972a9c
--- /dev/null
+++ b/kerby-backend/ldap-backend/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed 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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-backend</artifactId>
+ <version>1.0.0-RC3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>ldap-backend</artifactId>
+
+ <name>Ldap identity backend</name>
+ <description>Ldap identity backend</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-config</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-identity</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.api</groupId>
+ <artifactId>api-ldap-client-api</artifactId>
+ <version>${ldap.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.api</groupId>
+ <artifactId>api-util</artifactId>
+ <version>${ldap.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.api</groupId>
+ <artifactId>api-ldap-model</artifactId>
+ <version>${ldap.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-core-api</artifactId>
+ <version>${apacheds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-kerberos-codec</artifactId>
+ <version>${apacheds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-protocol-ldap</artifactId>
+ <version>${apacheds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>apacheds-test-framework</artifactId>
+ <version>${apacheds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.directory.server</groupId>
+ <artifactId>ldap-client-test</artifactId>
+ <version>${apacheds.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-identity-test</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityBackend.java
----------------------------------------------------------------------
diff --git a/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityBackend.java b/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityBackend.java
new file mode 100644
index 0000000..1e087a9
--- /dev/null
+++ b/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityBackend.java
@@ -0,0 +1,351 @@
+/**
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.EntryCursor;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.message.ModifyRequest;
+import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.util.GeneralizedTime;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.apache.directory.shared.kerberos.KerberosAttribute;
+import org.apache.kerby.config.Config;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.AbstractIdentityBackend;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An LDAP based backend implementation.
+ */
+public class LdapIdentityBackend extends AbstractIdentityBackend {
+ //The LdapConnection, may be LdapNetworkConnection or LdapCoreSessionConnection
+ private LdapConnection connection;
+ //This is used as a flag to represent the connection whether is
+ // LdapNetworkConnection object or not
+ private boolean isLdapNetworkConnection;
+ private static final Logger LOG = LoggerFactory.getLogger(LdapIdentityBackend.class);
+
+ public LdapIdentityBackend() {
+ this.isLdapNetworkConnection = true;
+ }
+
+ /**
+ * Constructing an instance using specified config that contains anything
+ * to be used to initialize an LdapConnection and necessary baseDn.
+ * @param config . The config is used to config the backend.
+ */
+ public LdapIdentityBackend(Config config) {
+ setConfig(config);
+ this.isLdapNetworkConnection = true;
+ }
+
+ /**
+ * Constructing an instance using a LdapConnection and a specified config
+ * that contains anything to be used to initialize a necessary baseDn.
+ * @param config The config is used to config the backend
+ * @param connection The connection to be used to handle the operations,
+ * may be a LdapNetworkConnection or a LdapCoreSessionConnection.
+ */
+ public LdapIdentityBackend(Config config,
+ LdapConnection connection) {
+ setConfig(config);
+ this.connection = connection;
+ }
+
+ /**
+ * Start the connection for the initialize()
+ */
+ private void startConnection() throws LdapException {
+ if (isLdapNetworkConnection == true) {
+ this.connection = new LdapNetworkConnection(getConfig().getString("host"),
+ getConfig().getInt("port"));
+ }
+ connection.bind(getConfig().getString("admin_dn"),
+ getConfig().getString("admin_pw"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doInitialize() throws KrbException {
+ LOG.info("Initializing the Ldap identity backend.");
+ try {
+ startConnection();
+ } catch (LdapException e) {
+ LOG.error("Failed to start connection with LDAP", e);
+ throw new KrbException("Failed to start connection with LDAP", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStop() throws KrbException {
+ try {
+ closeConnection();
+ } catch (IOException e) {
+ LOG.error("Failed to close connection with LDAP", e);
+ throw new KrbException("Failed to close connection with LDAP", e);
+ }
+ LOG.info("closed connection with LDAP.");
+ }
+
+ /**
+ * Close the connection for stop()
+ */
+ private void closeConnection() throws IOException {
+ if (connection.isConnected()) {
+ connection.close();
+ }
+ }
+
+ /**
+ * Convert a KerberosTime type obeject to a generalized time form of String
+ * @param kerberosTime The kerberostime to convert
+ */
+ private String toGeneralizedTime(KerberosTime kerberosTime) {
+ GeneralizedTime generalizedTime = new GeneralizedTime(kerberosTime.getValue());
+ return generalizedTime.toString();
+ }
+
+ /**
+ * An inner class, used to encapsulate key information
+ */
+ static class KeysInfo {
+ private String[] etypes;
+ private byte[][] keys;
+ private String[] kvnos;
+
+ KeysInfo(KrbIdentity identity) throws KrbException {
+ Map<EncryptionType, EncryptionKey> keymap = identity.getKeys();
+ this.etypes = new String[keymap.size()];
+ this.keys = new byte[keymap.size()][];
+ this.kvnos = new String[keymap.size()];
+ int i = 0;
+ for (Map.Entry<EncryptionType, EncryptionKey> entryKey : keymap.entrySet()) {
+ etypes[i] = entryKey.getKey().getValue() + "";
+ try {
+ keys[i] = entryKey.getValue().encode();
+ } catch (IOException e) {
+ throw new KrbException("encode key failed", e);
+ }
+ kvnos[i] = entryKey.getValue().getKvno() + "";
+ i++;
+ }
+ }
+
+ public String[] getEtypes() {
+ return etypes;
+ }
+
+ public byte[][] getKeys() {
+ return keys;
+ }
+
+ public String[] getKvnos() {
+ return kvnos;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doAddIdentity(KrbIdentity identity) throws KrbException {
+ String principalName = identity.getPrincipalName();
+ String[] names = principalName.split("@");
+ Entry entry = new DefaultEntry();
+ KeysInfo keysInfo = new KeysInfo(identity);
+ try {
+ Dn dn = toDn(principalName);
+ entry.setDn(dn);
+ entry.add("objectClass", "top", "person", "inetOrgPerson",
+ "krb5principal", "krb5kdcentry");
+ entry.add("cn", names[0]);
+ entry.add("sn", names[0]);
+ entry.add(KerberosAttribute.KRB5_KEY_AT, keysInfo.getKeys());
+ entry.add("krb5EncryptionType", keysInfo.getEtypes());
+ entry.add(KerberosAttribute.KRB5_PRINCIPAL_NAME_AT, principalName);
+ entry.add(KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT,
+ identity.getKeyVersion() + "");
+ entry.add("krb5KDCFlags", "" + identity.getKdcFlags());
+ entry.add(KerberosAttribute.KRB5_ACCOUNT_DISABLED_AT, ""
+ + identity.isDisabled());
+ entry.add("createTimestamp",
+ toGeneralizedTime(identity.getCreatedTime()));
+ entry.add(KerberosAttribute.KRB5_ACCOUNT_LOCKEDOUT_AT, ""
+ + identity.isLocked());
+ entry.add(KerberosAttribute.KRB5_ACCOUNT_EXPIRATION_TIME_AT,
+ toGeneralizedTime(identity.getExpireTime()));
+ connection.add(entry);
+ } catch (LdapInvalidDnException e) {
+ LOG.error("Error occurred while adding identity", e);
+ throw new KrbException("Failed to add identity", e);
+ } catch (LdapException e) {
+ LOG.error("Error occurred while adding identity", e);
+ throw new KrbException("Failed to add identity", e);
+ }
+ return getIdentity(principalName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doGetIdentity(String principalName) throws KrbException {
+ KrbIdentity krbIdentity = new KrbIdentity(principalName);
+ try {
+ Dn dn = toDn(principalName);
+ Entry entry = connection.lookup(dn, "*", "+");
+ if (entry == null) {
+ return null;
+ }
+ LdapIdentityGetHelper getHelper = new LdapIdentityGetHelper(entry);
+ krbIdentity.setPrincipal(getHelper.getPrincipalName());
+ krbIdentity.setKeyVersion(getHelper.getKeyVersion());
+ krbIdentity.addKeys(getHelper.getKeys());
+ krbIdentity.setCreatedTime(getHelper.getCreatedTime());
+ krbIdentity.setExpireTime(getHelper.getExpireTime());
+ krbIdentity.setDisabled(getHelper.getDisabled());
+ krbIdentity.setKdcFlags(getHelper.getKdcFlags());
+ krbIdentity.setLocked(getHelper.getLocked());
+ } catch (LdapException e) {
+ throw new KrbException("Failed to retrieve identity", e);
+ } catch (ParseException e) {
+ throw new KrbException("Failed to retrieve identity", e);
+ } catch (IOException e) {
+ throw new KrbException("Failed to retrieve identity", e);
+ }
+
+ return krbIdentity;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doUpdateIdentity(KrbIdentity identity) throws KrbException {
+ String principalName = identity.getPrincipalName();
+ KeysInfo keysInfo = new KeysInfo(identity);
+ try {
+ Dn dn = toDn(principalName);
+ ModifyRequest modifyRequest = new ModifyRequestImpl();
+ modifyRequest.setName(dn);
+ modifyRequest.replace(KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT,
+ "" + identity.getKeyVersion());
+ modifyRequest.replace(KerberosAttribute.KRB5_KEY_AT, keysInfo.getKeys());
+ modifyRequest.replace("krb5EncryptionType", keysInfo.getEtypes());
+ modifyRequest.replace(KerberosAttribute.KRB5_PRINCIPAL_NAME_AT,
+ identity.getPrincipalName());
+ modifyRequest.replace(KerberosAttribute.KRB5_ACCOUNT_EXPIRATION_TIME_AT,
+ toGeneralizedTime(identity.getExpireTime()));
+ modifyRequest.replace(KerberosAttribute.KRB5_ACCOUNT_DISABLED_AT, ""
+ + identity.isDisabled());
+ modifyRequest.replace("krb5KDCFlags", "" + identity.getKdcFlags());
+ modifyRequest.replace(KerberosAttribute.KRB5_ACCOUNT_LOCKEDOUT_AT, ""
+ + identity.isLocked());
+ connection.modify(modifyRequest);
+ } catch (LdapException e) {
+ LOG.error("Error occurred while updating identity: " + principalName, e);
+ throw new KrbException("Failed to update identity", e);
+ }
+
+ return getIdentity(principalName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doDeleteIdentity(String principalName) throws KrbException {
+ try {
+ Dn dn = toDn(principalName);
+ connection.delete(dn);
+ } catch (LdapException e) {
+ LOG.error("Error occurred while deleting identity: " + principalName);
+ throw new KrbException("Failed to remove identity", e);
+ }
+ }
+
+ /**
+ * Used to convert a dn of String to a Dn object
+ * @param principalName The principal name to be convert.
+ * @return
+ * @throws org.apache.directory.api.ldap.model.exception.LdapInvalidDnException if a remote exception occurs.
+ */
+ private Dn toDn(String principalName) throws LdapInvalidDnException {
+ String[] names = principalName.split("@");
+ String uid = names[0];
+ Dn dn = new Dn(new Rdn("uid", uid), new Dn(getConfig().getString("base_dn")));
+ return dn;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Iterable<String> doGetIdentities() {
+ List<String> identityNames = new ArrayList<>();
+ EntryCursor cursor;
+ Entry entry;
+ try {
+ cursor = connection.search(getConfig().getString("base_dn"),
+ "(objectclass=*)", SearchScope.ONELEVEL, KerberosAttribute.KRB5_PRINCIPAL_NAME_AT);
+ if (cursor == null) {
+ return null;
+ }
+ while (cursor.next()) {
+ entry = cursor.get();
+ identityNames.add(entry.get(KerberosAttribute.KRB5_PRINCIPAL_NAME_AT).getString());
+ }
+ cursor.close();
+ Collections.sort(identityNames);
+ } catch (LdapException e) {
+ LOG.error("With LdapException when LdapConnection searching. " + e);
+ } catch (CursorException e) {
+ LOG.error("With CursorException when EntryCursor getting. " + e);
+ } catch (IOException e) {
+ LOG.error("With IOException when closing EntryCursor. " + e);
+ }
+ return identityNames;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityGetHelper.java
----------------------------------------------------------------------
diff --git a/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityGetHelper.java b/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityGetHelper.java
new file mode 100644
index 0000000..bc070dc
--- /dev/null
+++ b/kerby-backend/ldap-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/LdapIdentityGetHelper.java
@@ -0,0 +1,145 @@
+/**
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.util.GeneralizedTime;
+import org.apache.directory.shared.kerberos.KerberosAttribute;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class LdapIdentityGetHelper {
+ private Entry entry;
+ public LdapIdentityGetHelper(Entry entry) {
+ this.entry = entry;
+ }
+
+ /**
+ * Get principal name.
+ * @throws LdapInvalidAttributeValueException e
+ * @return principal name
+ */
+ public PrincipalName getPrincipalName() throws LdapInvalidAttributeValueException {
+ String principalNameStr = entry.get(KerberosAttribute.KRB5_PRINCIPAL_NAME_AT).getString();
+ PrincipalName principalName = new PrincipalName(principalNameStr);
+ return principalName;
+ }
+
+ /**
+ * Get key version.
+ * @throws LdapInvalidAttributeValueException e
+ * @return key version
+ */
+ public int getKeyVersion() throws LdapInvalidAttributeValueException {
+ String keyVersionStr = entry.get(KerberosAttribute.KRB5_KEY_VERSION_NUMBER_AT).getString();
+ int keyVersion = Integer.parseInt(keyVersionStr);
+ return keyVersion;
+ }
+
+ /**
+ * Get keys.
+ * @throws IOException e
+ * @return keys
+ */
+ public List<EncryptionKey> getKeys() throws IOException {
+ Iterator<Value<?>> iterator1 = entry.get(KerberosAttribute.KRB5_KEY_AT).iterator();
+ List<EncryptionKey> keys = new ArrayList<>();
+ while (iterator1.hasNext()) {
+ byte[] encryKey = iterator1.next().getBytes();
+ EncryptionKey key = new EncryptionKey();
+ key.decode(encryKey);
+ key.setKvno(1); // TODO: kvno should be correctly stored and retrieved
+ keys.add(key);
+ }
+ return keys;
+ }
+
+ /**
+ * Get created time.
+ * @throws LdapInvalidAttributeValueException e
+ * @throws ParseException e
+ * @return created time
+ */
+ public KerberosTime getCreatedTime() throws LdapInvalidAttributeValueException,
+ ParseException {
+ String createTime = entry.get("createTimestamp").getString();
+ return createKerberosTime(createTime);
+ }
+
+ /**
+ * Get expire time.
+ * @throws LdapInvalidAttributeValueException e
+ * @throws ParseException e
+ * @return the expire time
+ */
+ public KerberosTime getExpireTime() throws LdapInvalidAttributeValueException,
+ ParseException {
+ String expirationTime = entry.get(KerberosAttribute.KRB5_ACCOUNT_EXPIRATION_TIME_AT).getString();
+ return createKerberosTime(expirationTime);
+ }
+
+ /**
+ * Get whether disabled.
+ * @throws LdapInvalidAttributeValueException e
+ * @return whether this krb5 account is disabled
+ */
+ public boolean getDisabled() throws LdapInvalidAttributeValueException {
+ String disabled = entry.get(KerberosAttribute.KRB5_ACCOUNT_DISABLED_AT).getString();
+ return Boolean.parseBoolean(disabled);
+ }
+
+ /**
+ * Get kdc flags.
+ * @throws LdapInvalidAttributeValueException e
+ * @return kdc flags
+ */
+ public int getKdcFlags() throws LdapInvalidAttributeValueException {
+ String krb5KDCFlags = entry.get("krb5KDCFlags").getString();
+ return Integer.parseInt(krb5KDCFlags);
+ }
+
+ /**
+ * Get whether locked.
+ * @throws LdapInvalidAttributeValueException e
+ * @return whether the krb5 account is locked
+ */
+ public boolean getLocked() throws LdapInvalidAttributeValueException {
+ String lockedOut = entry.get(KerberosAttribute.KRB5_ACCOUNT_LOCKEDOUT_AT).getString();
+ return Boolean.parseBoolean(lockedOut);
+ }
+
+ /**
+ * Create kerberos time.
+ */
+ private KerberosTime createKerberosTime(String generalizedTime)
+ throws ParseException {
+ long time = new GeneralizedTime(generalizedTime).getTime();
+ return new KerberosTime(time);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractLdapIdentityBackendTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractLdapIdentityBackendTest.java b/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractLdapIdentityBackendTest.java
new file mode 100644
index 0000000..e65d506
--- /dev/null
+++ b/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/AbstractLdapIdentityBackendTest.java
@@ -0,0 +1,84 @@
+/**
+ * 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.kerby.kerberos.kerb.identity.backend;
+
+import org.apache.directory.server.core.api.DirectoryService;
+import org.apache.directory.server.ldap.LdapServer;
+import org.apache.kerby.kerberos.kdc.identitybackend.LdapIdentityBackend;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.junit.After;
+import org.junit.Test;
+
+public abstract class AbstractLdapIdentityBackendTest extends BackendTest {
+ protected LdapIdentityBackend backend;
+
+ /** The used DirectoryService instance */
+ private static DirectoryService service;
+
+ /** The used LdapServer instance */
+ private static LdapServer ldapServer;
+
+ public static DirectoryService getService() {
+ return service;
+ }
+
+ public static void setService(DirectoryService service) {
+ AbstractLdapIdentityBackendTest.service = service;
+ }
+
+ public static LdapServer getLdapServer() {
+ return ldapServer;
+ }
+
+ public static void setLdapServer(LdapServer ldapServer) {
+ AbstractLdapIdentityBackendTest.ldapServer = ldapServer;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ backend.stop();
+ backend.release();
+ }
+
+ @Test
+ public void testGet() throws KrbException {
+ testGet(backend);
+ }
+
+ @Test
+ public void testStore() throws KrbException {
+ testStore(backend);
+ }
+
+ @Test
+ public void testUpdate() throws KrbException {
+ testUpdate(backend);
+ }
+
+ @Test
+ public void testDelete() throws KrbException {
+ testDelete(backend);
+ }
+
+ @Test
+ public void testGetIdentities() throws KrbException {
+ testGetIdentities(backend);
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/DirectoryLdapIdentityBackendTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/DirectoryLdapIdentityBackendTest.java b/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/DirectoryLdapIdentityBackendTest.java
new file mode 100644
index 0000000..86960fe
--- /dev/null
+++ b/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/DirectoryLdapIdentityBackendTest.java
@@ -0,0 +1,77 @@
+/**
+ * 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.kerby.kerberos.kerb.identity.backend;
+
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.api.LdapCoreSessionConnection;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.apache.kerby.config.Conf;
+import org.apache.kerby.kerberos.kdc.identitybackend.LdapIdentityBackend;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+@RunWith(FrameworkRunner.class)
+@CreateDS(name = "KerberosKRBProtocolTest-class",
+ partitions =
+ {
+ @CreatePartition(
+ name = "example",
+ suffix = "dc=example,dc=com")
+ })
+@CreateLdapServer(
+ transports =
+ {
+ @CreateTransport(protocol = "LDAP", address = "127.0.0.1")
+ })
+@ApplyLdifs(
+ {
+ "dn: dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: domain",
+ "dc: example",
+ "dn: ou=users,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: users"
+ }
+)
+public class DirectoryLdapIdentityBackendTest extends AbstractLdapIdentityBackendTest {
+ private static final String BASE_DN = "ou=users,dc=example,dc=com";
+ private static final String ADMIN_DN = "uid=admin,ou=system";
+ private static final String ADMIN_PW = "secret";
+
+
+ @Before
+ public void setUp() throws Exception {
+ Conf config = new Conf();
+ config.setString("admin_dn", ADMIN_DN);
+ config.setString("admin_pw", ADMIN_PW);
+ config.setString("base_dn", BASE_DN);
+ LdapConnection connection = new LdapCoreSessionConnection(getService());
+ backend = new LdapIdentityBackend(config, connection);
+ backend.initialize();
+ backend.start();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/LdapIdentityBackendTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/LdapIdentityBackendTest.java b/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/LdapIdentityBackendTest.java
new file mode 100644
index 0000000..21551fd
--- /dev/null
+++ b/kerby-backend/ldap-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/LdapIdentityBackendTest.java
@@ -0,0 +1,75 @@
+/**
+ * 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.kerby.kerberos.kerb.identity.backend;
+
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.annotations.CreateDS;
+import org.apache.directory.server.core.annotations.CreatePartition;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.apache.kerby.config.Conf;
+import org.apache.kerby.kerberos.kdc.identitybackend.LdapIdentityBackend;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
+@RunWith(FrameworkRunner.class)
+@CreateDS(name = "KerberosKRBProtocolTest-class",
+ partitions =
+ {
+ @CreatePartition(
+ name = "example",
+ suffix = "dc=example,dc=com")
+ })
+@CreateLdapServer(
+ transports =
+ {
+ @CreateTransport(protocol = "LDAP", address = "127.0.0.1")
+ })
+@ApplyLdifs(
+ {
+ "dn: dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: domain",
+ "dc: example",
+ "dn: ou=users,dc=example,dc=com",
+ "objectClass: top",
+ "objectClass: organizationalUnit",
+ "ou: users"
+ }
+)
+public class LdapIdentityBackendTest extends AbstractLdapIdentityBackendTest {
+ private static final String BASE_DN = "ou=users,dc=example,dc=com";
+ private static final String ADMIN_DN = "uid=admin,ou=system";
+ private static final String ADMIN_PW = "secret";
+
+ @Before
+ public void setUp() throws Exception {
+ Conf config = new Conf();
+ config.setString("host", "127.0.0.1");
+ config.setInt("port", getLdapServer().getPort());
+ config.setString("admin_dn", ADMIN_DN);
+ config.setString("admin_pw", ADMIN_PW);
+ config.setString("base_dn", BASE_DN);
+ backend = new LdapIdentityBackend(config);
+ backend.initialize();
+ backend.start();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/mavibot-backend/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot-backend/pom.xml b/kerby-backend/mavibot-backend/pom.xml
new file mode 100644
index 0000000..5375a07
--- /dev/null
+++ b/kerby-backend/mavibot-backend/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-backend</artifactId>
+ <version>1.0.0-RC3-SNAPSHOT</version>
+ </parent>
+ <artifactId>mavibot-backend</artifactId>
+ <name>Mavibot based backend</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.directory.mavibot</groupId>
+ <artifactId>mavibot</artifactId>
+ <version>1.0.0-M8</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-config</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-identity</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-identity-test</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentityComparator.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentityComparator.java b/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentityComparator.java
new file mode 100644
index 0000000..bce3033
--- /dev/null
+++ b/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentityComparator.java
@@ -0,0 +1,43 @@
+/*
+ * 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.kerby;
+
+import java.util.Comparator;
+
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+
+/**
+ * Comparator for KrbIdentity
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public final class KrbIdentityComparator implements Comparator<KrbIdentity> {
+
+ public static final KrbIdentityComparator INSTANCE = new KrbIdentityComparator();
+
+ private KrbIdentityComparator() {
+ }
+
+ @Override
+ public int compare(KrbIdentity o1, KrbIdentity o2) {
+ return o1.getPrincipalName().compareTo(o2.getPrincipalName());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentitySerializer.java b/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
new file mode 100644
index 0000000..dc3df02
--- /dev/null
+++ b/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
@@ -0,0 +1,180 @@
+/*
+ * 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.kerby;
+
+import org.apache.directory.mavibot.btree.serializer.BufferHandler;
+import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.IntSerializer;
+import org.apache.directory.mavibot.btree.serializer.LongSerializer;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * Serializer for KrbIdentity.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class KrbIdentitySerializer implements ElementSerializer<KrbIdentity> {
+ /** the static instance of the serializer */
+ public static final KrbIdentitySerializer INSTANCE = new KrbIdentitySerializer();
+
+ /** comparator for KrbIdentity */
+ private KrbIdentityComparator comparator = KrbIdentityComparator.INSTANCE;
+
+ @Override
+ public byte[] serialize(KrbIdentity entry) {
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+ try {
+ // the principalName
+ out.write(StringSerializer.INSTANCE.serialize(entry.getPrincipalName()));
+
+ // key version
+ out.write(IntSerializer.serialize(entry.getKeyVersion()));
+
+ out.write(IntSerializer.serialize(entry.getKdcFlags()));
+
+ // mask for disabled and lock flags
+ byte mask = 0;
+
+ if (entry.isDisabled()) {
+ mask |= 1 << 1;
+ }
+
+ if (entry.isLocked()) {
+ mask |= 1 << 2;
+ }
+
+ out.write(mask);
+
+ // creation time
+ out.write(LongSerializer.serialize(entry.getCreatedTime().getTime()));
+
+ // expiration time
+ out.write(LongSerializer.serialize(entry.getExpireTime().getTime()));
+
+ Map<EncryptionType, EncryptionKey> keys = entry.getKeys();
+ // num keys
+ out.write(IntSerializer.serialize(keys.size()));
+
+ for (EncryptionKey ek : keys.values()) {
+ int type = ek.getKeyType().getValue();
+ out.write(IntSerializer.serialize(type));
+ byte[] data = ek.getKeyData();
+ out.write(IntSerializer.serialize(data.length));
+ out.write(data);
+ }
+
+ return out.toByteArray();
+ } catch (Exception e) {
+ throw new IllegalStateException("Failed to serialize the identity " + entry);
+ }
+ }
+
+ @Override
+ public KrbIdentity deserialize(BufferHandler bufferHandler)
+ throws IOException {
+ return fromBytes(bufferHandler.getBuffer());
+ }
+
+ @Override
+ public KrbIdentity deserialize(ByteBuffer buffer) throws IOException {
+ KrbIdentity id = null;
+
+ String principal = StringSerializer.INSTANCE.deserialize(buffer);
+
+ id = new KrbIdentity(principal);
+
+ int kvno = IntSerializer.INSTANCE.deserialize(buffer);
+ id.setKeyVersion(kvno);
+
+ int flags = IntSerializer.INSTANCE.deserialize(buffer);
+ id.setKdcFlags(flags);
+
+ byte mask = buffer.get();
+
+ if ((mask & 2) != 0) {
+ id.setDisabled(true);
+ }
+
+ if ((mask & 4) != 0) {
+ id.setLocked(true);
+ }
+
+ long creationTime = LongSerializer.INSTANCE.deserialize(buffer);
+ id.setCreatedTime(new KerberosTime(creationTime));
+
+ long exprTime = LongSerializer.INSTANCE.deserialize(buffer);
+ id.setExpireTime(new KerberosTime(exprTime));
+
+ int numKeys = IntSerializer.INSTANCE.deserialize(buffer);
+
+ for (int i = 0; i < numKeys; i++) {
+ int keyType = IntSerializer.INSTANCE.deserialize(buffer);
+ int keyLen = IntSerializer.INSTANCE.deserialize(buffer);
+
+ byte[] keyData = new byte[keyLen];
+ buffer.get(keyData);
+
+ EncryptionKey ek = new EncryptionKey(keyType, keyData);
+
+ id.addKey(ek);
+ }
+
+ return id;
+ }
+
+ @Override
+ public KrbIdentity fromBytes(byte[] buffer) throws IOException {
+ ByteBuffer buf = ByteBuffer.wrap(buffer);
+ return deserialize(buf);
+ }
+
+ @Override
+ public KrbIdentity fromBytes(byte[] buffer, int pos) throws IOException {
+ ByteBuffer buf = ByteBuffer.wrap(buffer, pos, buffer.length - pos);
+ return deserialize(buf);
+ }
+
+ @Override
+ public int compare(KrbIdentity type1, KrbIdentity type2) {
+ return comparator.compare(type1, type2);
+ }
+
+ @Override
+ public Comparator<KrbIdentity> getComparator() {
+ return comparator;
+ }
+
+ @Override
+ public Class<?> getType() {
+ return KrbIdentity.class;
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/MavibotBackend.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/MavibotBackend.java b/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/MavibotBackend.java
new file mode 100644
index 0000000..7c31617
--- /dev/null
+++ b/kerby-backend/mavibot-backend/src/main/java/org/apache/kerby/MavibotBackend.java
@@ -0,0 +1,202 @@
+/*
+ * 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.kerby;
+
+import org.apache.directory.mavibot.btree.BTree;
+import org.apache.directory.mavibot.btree.BTreeFactory;
+import org.apache.directory.mavibot.btree.BTreeTypeEnum;
+import org.apache.directory.mavibot.btree.KeyCursor;
+import org.apache.directory.mavibot.btree.PersistedBTreeConfiguration;
+import org.apache.directory.mavibot.btree.RecordManager;
+import org.apache.directory.mavibot.btree.Tuple;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.AbstractIdentityBackend;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A backend based on Apache Mavibot(an MVCC BTree library).
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotBackend extends AbstractIdentityBackend {
+ //Name of the database
+ private static final String DATA_TREE = "kerby-data";
+ // Name of the database file
+ private static final String DATABASE_NAME = "kerby-data.db";
+ private static final Logger LOG = LoggerFactory.getLogger(MavibotBackend.class);
+ //The RecordManager of Mavibot
+ private RecordManager rm;
+ //The BTree holding all data
+ private BTree<String, KrbIdentity> database;
+
+ /**
+ * Creates a new instance of MavibotBackend.
+ *
+ * @param location
+ * the File handle pointing to the database file or the directory
+ * where it is present
+ * @throws Exception e
+ */
+ public MavibotBackend(File location) throws Exception {
+ String dbPath = location.getAbsolutePath();
+
+ LOG.info("Initializing the mavibot backend");
+
+ if (!location.exists() && !location.mkdirs()) {
+ throw new KrbException("Can't create location file");
+ }
+
+ if (location.isDirectory()) {
+ dbPath += File.separator + DATABASE_NAME;
+ }
+
+ rm = new RecordManager(dbPath);
+
+ if (rm.getManagedTrees().contains(DATA_TREE)) {
+ database = rm.getManagedTree(DATA_TREE);
+ } else {
+ PersistedBTreeConfiguration<String, KrbIdentity> config =
+ new PersistedBTreeConfiguration<String, KrbIdentity>();
+ // _no_ duplicates
+ config.setAllowDuplicates(false);
+ config.setBtreeType(BTreeTypeEnum.PERSISTED);
+ config.setFilePath(dbPath);
+ config.setKeySerializer(StringSerializer.INSTANCE);
+ config.setName(DATA_TREE);
+ config.setValueSerializer(KrbIdentitySerializer.INSTANCE);
+
+ database = BTreeFactory.createPersistedBTree(config);
+ rm.manage(database);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Iterable<String> doGetIdentities() throws KrbException {
+ List<String> keys = new ArrayList<String>();
+ KeyCursor<String> cursor = null;
+
+ try {
+ cursor = database.browseKeys();
+ while (cursor.hasNext()) {
+ keys.add(cursor.next());
+ }
+ } catch (Exception e) {
+ throw new KrbException("Errors occurred while fetching the principals", e);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+
+ return keys;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected KrbIdentity doGetIdentity(String principalName) throws KrbException {
+ try {
+ return database.get(principalName);
+ } catch (KeyNotFoundException e) {
+ LOG.debug("Identity {} doesn't exist", principalName);
+ return null;
+ } catch (IOException e) {
+ throw new KrbException("Failed to get the identity " + principalName);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected synchronized KrbIdentity doAddIdentity(KrbIdentity identity) throws KrbException {
+ String p = identity.getPrincipalName();
+ try {
+ if (database.hasKey(p)) {
+ throw new KrbException("Identity already exists " + p);
+ }
+
+ return database.insert(p, identity);
+ } catch (KeyNotFoundException e) {
+ throw new KrbException("No such identity exists " + p);
+ } catch (IOException e) {
+ throw new KrbException("Failed to add the identity " + p);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected synchronized KrbIdentity doUpdateIdentity(KrbIdentity identity) throws KrbException {
+ String p = identity.getPrincipalName();
+ try {
+ if (!database.hasKey(p)) {
+ throw new KrbException("No identity found with the principal " + p);
+ }
+
+ database.delete(p);
+
+ return database.insert(p, identity);
+ } catch (Exception e) {
+ throw new KrbException("Failed to update the identity " + p);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doDeleteIdentity(String principalName) throws KrbException {
+ try {
+ Tuple<String, KrbIdentity> t = database.delete(principalName);
+ if (t == null) {
+ throw new KrbException("Not existing, identity = " + principalName);
+ }
+ } catch (IOException e) {
+ throw new KrbException("Failed to delete the identity " + principalName);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void doStop() throws KrbException {
+ try {
+ rm.close();
+ } catch (IOException e) {
+ throw new KrbException("Failed to close the database", e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java b/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java
new file mode 100644
index 0000000..4c82bfb
--- /dev/null
+++ b/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.kerby;
+
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.junit.Test;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests for KrbIdentity serializer.
+ *
+ * @author <a href="mailto:kerby@directory.apache.org">Apache Kerby Project</a>
+ */
+public class KrbIdentitySerializerTest {
+
+ private KrbIdentitySerializer serializer = KrbIdentitySerializer.INSTANCE;
+
+ @Test
+ public void testSerialization() throws Exception {
+ KrbIdentity entry = new KrbIdentity("hnelson@EXAMPLE.COM");
+ entry.setCreatedTime(new KerberosTime(System.currentTimeMillis()));
+ entry.setDisabled(true);
+ entry.setKeyVersion(1);
+ entry.setLocked(true);
+
+ byte[] junk = new byte[11];
+ Arrays.fill(junk, (byte) 1);
+ EncryptionKey key1 = new EncryptionKey(EncryptionType.AES128_CTS, junk);
+ entry.addKey(key1);
+
+ EncryptionKey key2 = new EncryptionKey(EncryptionType.AES128_CTS_HMAC_SHA1_96, junk);
+ entry.addKey(key2);
+
+ byte[] serialized = serializer.serialize(entry);
+
+ KrbIdentity deserialized = serializer.fromBytes(serialized);
+ verifyEquality(entry, deserialized);
+
+ deserialized = serializer.fromBytes(serialized, 0);
+ verifyEquality(entry, deserialized);
+
+ deserialized = serializer.deserialize(ByteBuffer.wrap(serialized));
+ verifyEquality(entry, deserialized);
+
+ try {
+ deserialized = serializer.fromBytes(serialized, 1);
+ fail("shouldn't deserialize");
+ } catch (Exception e) {
+ // expected
+ System.out.println(e);
+ }
+ }
+
+
+ private void verifyEquality(KrbIdentity expected, KrbIdentity actual) {
+ assertNotNull(actual);
+ assertEquals(expected.getPrincipalName(), actual.getPrincipalName());
+ assertEquals(expected.getCreatedTime().getTime(), actual.getCreatedTime().getTime());
+ assertEquals(expected.getExpireTime().getTime(), actual.getExpireTime().getTime());
+ assertEquals(expected.isDisabled(), actual.isDisabled());
+ assertEquals(expected.isLocked(), actual.isLocked());
+ assertEquals(expected.getKeyVersion(), actual.getKeyVersion());
+ assertEquals(expected.getKdcFlags(), actual.getKdcFlags());
+ assertEquals(expected.getKeys().size(), actual.getKeys().size());
+
+ Map<EncryptionType, EncryptionKey> exKeys = expected.getKeys();
+ Map<EncryptionType, EncryptionKey> acKeys = actual.getKeys();
+ for (EncryptionType et : exKeys.keySet()) {
+ EncryptionKey exKey = exKeys.get(et);
+ EncryptionKey acKey = acKeys.get(et);
+
+ assertEquals(exKey.getKvno(), acKey.getKvno());
+ assertEquals(exKey.getKeyType(), acKey.getKeyType());
+ boolean equal = Arrays.equals(exKey.getKeyData(), acKey.getKeyData());
+ assertTrue(equal);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/MavibotBackendTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/MavibotBackendTest.java b/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/MavibotBackendTest.java
new file mode 100644
index 0000000..6fa17dc
--- /dev/null
+++ b/kerby-backend/mavibot-backend/src/test/java/org/apache/kerby/MavibotBackendTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.kerby;
+
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendTestBase;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendTestUtil;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for MavibotBackend.
+ *
+ * @author <a href="mailto:kerby@directory.apache.org">Apache Kerby Project</a>
+ */
+public class MavibotBackendTest extends BackendTestBase {
+ private static TemporaryFolder tmpFolder = new TemporaryFolder();
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ tmpFolder.create();
+
+ File dbFile = tmpFolder.newFile();
+ backend = new MavibotBackend(dbFile);
+ backend.initialize();
+ }
+
+ @AfterClass
+ public static void tearDown() throws KrbException {
+ tmpFolder.delete();
+ }
+
+ // overriding this cause MavibotBackend doesn't support range search
+ @Override
+ protected void testGetIdentities(IdentityBackend backend) throws KrbException {
+ KrbIdentity[] identities = BackendTestUtil.createManyIdentities();
+
+ for (KrbIdentity identity : identities) {
+ backend.addIdentity(identity);
+ }
+
+ // clear the identity cache.
+ backend.release();
+
+ List<String> principals = new LinkedList<>();
+ Iterator<String> iterator = backend.getIdentities().iterator();
+ while (iterator.hasNext()) {
+ principals.add(iterator.next());
+ }
+ assertThat(principals).hasSize(identities.length);
+
+ for (KrbIdentity entry : identities) {
+ assertTrue(principals.contains(entry.getPrincipalName()));
+ }
+
+ for (KrbIdentity identity : identities) {
+ backend.deleteIdentity(identity.getPrincipalName());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-backend/pom.xml b/kerby-backend/pom.xml
index 7b7c9e6..d0174f2 100644
--- a/kerby-backend/pom.xml
+++ b/kerby-backend/pom.xml
@@ -26,7 +26,10 @@
<packaging>pom</packaging>
<modules>
+ <module>ldap-backend</module>
+ <module>mavibot-backend</module>
<module>json-backend</module>
+ <module>zookeeper-backend</module>
</modules>
<dependencies>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/pom.xml b/kerby-backend/zookeeper-backend/pom.xml
new file mode 100644
index 0000000..960ed1c
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed 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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-backend</artifactId>
+ <version>1.0.0-RC3-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>zookeeper-backend</artifactId>
+ <name>Zookeeper identity backend</name>
+ <description>Zookeeper identity backend</description>
+ <packaging>jar</packaging>
+
+ <properties>
+ <zookeeper.version>3.4.6</zookeeper.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-config</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-identity</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.zookeeper</groupId>
+ <artifactId>zookeeper</artifactId>
+ <version>${zookeeper.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-identity-test</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-crypto</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/43ab5afe/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNode.java
----------------------------------------------------------------------
diff --git a/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNode.java b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNode.java
new file mode 100644
index 0000000..883d9f8
--- /dev/null
+++ b/kerby-backend/zookeeper-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/IdentityZNode.java
@@ -0,0 +1,346 @@
+/**
+ * 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.kerby.kerberos.kdc.identitybackend;
+
+import org.apache.kerby.kerberos.kerb.crypto.util.BytesUtil;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.apache.kerby.util.Utf8;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooKeeper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class IdentityZNode {
+ private static final Logger LOG = LoggerFactory.getLogger(IdentityZNode.class);
+ private ZooKeeper zk;
+ private String identityName;
+
+ public IdentityZNode(ZooKeeper zk, String identityName) {
+ this.zk = zk;
+ this.identityName = identityName;
+ }
+
+ public boolean exist() throws KeeperException {
+ String znode = IdentityZNodeHelper.getIndentityZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public PrincipalName getPrincipalName() throws KeeperException {
+ String znode = IdentityZNodeHelper.getPrincipalNameZnode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data;
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+ if (data != null) {
+ return new PrincipalName(Utf8.toString(data));
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return null;
+ }
+ }
+
+ public void setPrincipalName(String principal) throws KeeperException {
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getPrincipalNameZnode(this.identityName),
+ Utf8.toBytes(principal));
+ }
+
+ public int getKeyVersion() throws KeeperException {
+ String znode = IdentityZNodeHelper.getKeyVersionZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ return BytesUtil.bytes2int(data, true);
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return -1;
+ }
+ }
+
+ public void setKeyVersion(int keyVersion) throws KeeperException {
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getKeyVersionZNode(this.identityName),
+ BytesUtil.int2bytes(keyVersion, true));
+ }
+
+ public int getKdcFlags() throws KeeperException {
+ String znode = IdentityZNodeHelper.getKdcFlagsZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ return BytesUtil.bytes2int(data, true);
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return -1;
+ }
+ }
+
+ public void setKdcFlags(int kdcFlags) throws KeeperException {
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getKdcFlagsZNode(this.identityName),
+ BytesUtil.int2bytes(kdcFlags, true));
+ }
+
+ public boolean getDisabled() throws KeeperException {
+ String znode = IdentityZNodeHelper.getDisabledZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ int disabled = BytesUtil.bytes2int(data, true);
+ return disabled == 1;
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return false;
+ }
+ }
+
+ public void setDisabled(boolean disabled) throws KeeperException {
+ int value;
+ if (disabled) {
+ value = 1;
+ } else {
+ value = 0;
+ }
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getDisabledZNode(this.identityName),
+ BytesUtil.int2bytes(value, true));
+ }
+
+ public boolean getLocked() throws KeeperException {
+ String znode = IdentityZNodeHelper.getLockedZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ int locked = BytesUtil.bytes2int(data, true);
+ return locked == 1;
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return false;
+ }
+ }
+
+ public void setLocked(boolean locked) throws KeeperException {
+ int value;
+ if (locked) {
+ value = 1;
+ } else {
+ value = 0;
+ }
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getLockedZNode(this.identityName),
+ BytesUtil.int2bytes(value, true));
+ }
+
+ public KerberosTime getExpireTime() throws KeeperException {
+ String znode = IdentityZNodeHelper.getExpireTimeZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ long time = BytesUtil.bytes2long(data, true);
+ return new KerberosTime(time);
+ } else {
+ LOG.warn("can't get the date from znode:" + znode);
+ return null;
+ }
+ }
+
+ public void setExpireTime(KerberosTime time) throws KeeperException {
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getExpireTimeZNode(this.identityName),
+ BytesUtil.long2bytes(time.getTime(), true));
+ }
+
+ public KerberosTime getCreatedTime() throws KeeperException {
+ String znode = IdentityZNodeHelper.getCreatedTimeZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ long time = BytesUtil.bytes2long(data, true);
+ return new KerberosTime(time);
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return null;
+ }
+ }
+
+ public void setCreatedTime(KerberosTime time) throws KeeperException {
+ ZKUtil.createSetData(this.zk,
+ IdentityZNodeHelper.getCreatedTimeZNode(this.identityName),
+ BytesUtil.long2bytes(time.getTime(), true));
+ }
+
+ public EncryptionType getEncryptionKeyType(String type) throws KeeperException {
+ String znode = IdentityZNodeHelper.getEncryptionKeyTypeZNode(this.identityName, type);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ return EncryptionType.fromName(Utf8.toString(data));
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return null;
+ }
+ }
+
+ public byte[] getEncryptionKey(String type) throws KeeperException {
+ String znode = IdentityZNodeHelper.getEncryptionKeyZNode(this.identityName, type);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data == null) {
+ LOG.warn("can't get the date from znode: " + znode);
+ }
+ return data;
+ }
+
+ public int getEncryptionKeyNo(String type) throws KeeperException {
+ String znode = IdentityZNodeHelper.getEncryptionKeyNoZNode(this.identityName, type);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ byte[] data = new byte[0];
+ try {
+ data = ZKUtil.getData(this.zk, znode);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (data != null) {
+ return BytesUtil.bytes2int(data, true);
+ } else {
+ LOG.warn("can't get the date from znode: " + znode);
+ return -1;
+ }
+ }
+
+ public List<EncryptionKey> getKeys() throws KeeperException {
+ String znode = IdentityZNodeHelper.getKeysZNode(this.identityName);
+ if (ZKUtil.checkExists(this.zk, znode) == -1) {
+ throw new IllegalArgumentException("The znode " + znode + " is not found");
+ }
+ List<String> typeNames = ZKUtil.listChildrenNoWatch(this.zk, znode);
+ List<EncryptionKey> keys = new ArrayList<EncryptionKey>(typeNames.size());
+ for (String typeName : typeNames) {
+ byte[] key = getEncryptionKey(typeName);
+ EncryptionKey encryptionKey = new EncryptionKey();
+ try {
+ encryptionKey.decode(key);
+ } catch (IOException e) {
+ LOG.error("Fail to decode the encryption key. " + e);
+ }
+ encryptionKey.setKvno(getEncryptionKeyNo(typeName));
+ keys.add(encryptionKey);
+ }
+ return keys;
+ }
+
+ public void setKeys(Map<EncryptionType, EncryptionKey> keys) throws KeeperException, IOException {
+ if (ZKUtil.checkExists(this.zk, IdentityZNodeHelper.getKeysZNode(this.identityName)) == -1) {
+ ZKUtil.createWithParents(this.zk, IdentityZNodeHelper.getKeysZNode(this.identityName));
+ }
+ Iterator<Map.Entry<EncryptionType, EncryptionKey>> it = keys.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<EncryptionType, EncryptionKey> pair = it.next();
+ EncryptionType key = (EncryptionType) pair.getKey();
+ ZKUtil.createWithParents(this.zk, IdentityZNodeHelper.getKeyTypeZNode(this.identityName, key.getName()));
+ EncryptionKey value = (EncryptionKey) pair.getValue();
+ ZKUtil.createSetData(this.zk, IdentityZNodeHelper.getEncryptionKeyZNode(this.identityName, key.getName()),
+ value.encode());
+ ZKUtil.createSetData(this.zk, IdentityZNodeHelper.getEncryptionKeyNoZNode(this.identityName, key.getName()),
+ BytesUtil.int2bytes(value.getKvno(), true));
+ }
+ }
+
+ public void deleteIdentity() throws KeeperException {
+ ZKUtil.deleteNodeRecursively(this.zk, IdentityZNodeHelper.getIndentityZNode(this.identityName));
+ }
+}