directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From plusplusjia...@apache.org
Subject [2/2] directory-kerby git commit: Revert "Backup the backends to backup-for-backends branch."
Date Wed, 19 Apr 2017 03:41:26 GMT
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 <jiajia.li@intel.com>
Authored: Wed Apr 19 11:48:33 2017 +0800
Committer: plusplusjiajia <jiajia.li@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));
+    }
+}


Mime
View raw message