You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2015/07/02 10:15:45 UTC

[5/5] directory-kerby git commit: implementation and tests

implementation and tests


Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/d534db85
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/d534db85
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/d534db85

Branch: refs/heads/master
Commit: d534db856a2f403407462a2da7f5bd1e7bdc0113
Parents: c6e1309
Author: Kiran Ayyagari <ka...@apache.org>
Authored: Thu Jul 2 16:14:47 2015 +0800
Committer: Kiran Ayyagari <ka...@apache.org>
Committed: Thu Jul 2 16:14:47 2015 +0800

----------------------------------------------------------------------
 .../org/apache/kerby/KrbIdentitySerializer.java | 121 +++++++++++++++++--
 .../java/org/apache/kerby/MavibotBackend.java   | 117 ++++++++++++++++--
 .../apache/kerby/KrbIdentitySerializerTest.java | 106 ++++++++++++++++
 .../org/apache/kerby/MavibotBackendTest.java    |  89 ++++++++++++++
 4 files changed, 419 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/d534db85/kerby-backend/mavibot/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot/src/main/java/org/apache/kerby/KrbIdentitySerializer.java b/kerby-backend/mavibot/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
index b8a494a..0452ccd 100644
--- a/kerby-backend/mavibot/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
+++ b/kerby-backend/mavibot/src/main/java/org/apache/kerby/KrbIdentitySerializer.java
@@ -19,16 +19,24 @@
  */
 package org.apache.kerby;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Comparator;
+import java.util.Map;
 
 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.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
 
 /**
- * Serializer class for KrbIdentity.
+ * Serializer for KrbIdentity.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
@@ -40,29 +48,128 @@ public class KrbIdentitySerializer implements ElementSerializer<KrbIdentity> {
     private KrbIdentityComparator comparator = KrbIdentityComparator.INSTANCE;
 
     @Override
-    public byte[] serialize(KrbIdentity key) {
-        return null;
+    public byte[] serialize(KrbIdentity entry) {
+        
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
+        try {
+            //out.write(IntSerializer.serialize(0)); // placeholder for length prefix
+            
+            // 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);
+            }
+            
+            byte[] data = out.toByteArray();
+            //int length = data.length - 4; // remove the prefix bytes
+            
+            // put the actual length
+            //IntSerializer.serialize(data, 0, length);
+            
+            return data;
+        }
+        catch(Exception e) {
+            throw new IllegalStateException("Failed to serialize the identity " + entry);
+        }
     }
 
     @Override
     public KrbIdentity deserialize(BufferHandler bufferHandler)
             throws IOException {
-        return null;
+        return fromBytes(bufferHandler.getBuffer());
     }
 
     @Override
     public KrbIdentity deserialize(ByteBuffer buffer) throws IOException {
-        return null;
+        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 {
-        return null;
+        ByteBuffer buf = ByteBuffer.wrap(buffer);
+        return deserialize(buf);
     }
 
     @Override
     public KrbIdentity fromBytes(byte[] buffer, int pos) throws IOException {
-        return null;
+        ByteBuffer buf = ByteBuffer.wrap(buffer, pos, buffer.length - pos);
+        return deserialize(buf);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/d534db85/kerby-backend/mavibot/src/main/java/org/apache/kerby/MavibotBackend.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot/src/main/java/org/apache/kerby/MavibotBackend.java b/kerby-backend/mavibot/src/main/java/org/apache/kerby/MavibotBackend.java
index 50aef65..c000b38 100644
--- a/kerby-backend/mavibot/src/main/java/org/apache/kerby/MavibotBackend.java
+++ b/kerby-backend/mavibot/src/main/java/org/apache/kerby/MavibotBackend.java
@@ -19,13 +19,26 @@
  */
 package org.apache.kerby;
 
-import org.apache.directory.mavibot.btree.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.management.openmbean.KeyAlreadyExistsException;
+
+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.identity.KrbIdentity;
 import org.apache.kerby.kerberos.kerb.identity.backend.AbstractIdentityBackend;
-
-import java.io.File;
-import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A backend based on Apache Mavibot(an MVCC BTree library).
@@ -45,6 +58,8 @@ public class MavibotBackend extends AbstractIdentityBackend {
     /** name of the database file */
     private static final String DATABASE_NAME = "kerby-data.db";
 
+    private static final Logger LOG = LoggerFactory.getLogger(MavibotBackend.class);
+    
     /**
      * Creates a new instance of MavibotBackend.
      *
@@ -56,6 +71,8 @@ public class MavibotBackend extends AbstractIdentityBackend {
     public MavibotBackend(File location) throws Exception {
         String dbPath = location.getAbsolutePath();
 
+        LOG.info("Initializing the mavibot backend");
+        
         if (!location.exists()) {
             location.mkdirs();
         }
@@ -88,7 +105,27 @@ public class MavibotBackend extends AbstractIdentityBackend {
      */
     @Override
     public List<String> getIdentities(int start, int limit) {
-        return null;
+        
+        List<String> keys = new ArrayList<String>();
+        
+        KeyCursor<String> cursor = null;
+        
+        try {
+            cursor = database.browseKeys();
+            while(cursor.hasNext()) {
+                keys.add(cursor.next());
+            }
+        }
+        catch(Exception e) {
+            LOG.debug("Errors occurred while fetching the principals", e);
+        }
+        finally {
+            if(cursor != null) {
+                cursor.close();
+            }
+        }
+        
+        return keys;
     }
 
     /**
@@ -96,6 +133,18 @@ public class MavibotBackend extends AbstractIdentityBackend {
      */
     @Override
     protected KrbIdentity doGetIdentity(String principalName) {
+        
+        try {
+            return database.get(principalName);
+        }
+        catch(KeyNotFoundException e) {
+            LOG.debug("Identity {} doesn't exist", principalName);
+        }
+        catch(IOException e) {
+            LOG.warn("Failed to get the identity {}", principalName);
+            throw new RuntimeException(e);
+        }
+        
         return null;
     }
 
@@ -104,7 +153,20 @@ public class MavibotBackend extends AbstractIdentityBackend {
      */
     @Override
     protected KrbIdentity doAddIdentity(KrbIdentity identity) {
-        return null;
+        
+        String p = identity.getPrincipalName();
+        try {
+            return database.insert(p, identity);
+        }
+        catch(KeyAlreadyExistsException e) {
+            LOG.debug("Identity {} already exists", p);
+            LOG.debug("", e);
+            return null;
+        }
+        catch(IOException e) {
+            LOG.warn("Failed to add the identity {}", p);
+            throw new RuntimeException(e);
+        }
     }
 
     /**
@@ -112,7 +174,27 @@ public class MavibotBackend extends AbstractIdentityBackend {
      */
     @Override
     protected KrbIdentity doUpdateIdentity(KrbIdentity identity) {
-        return null;
+        
+        String p = identity.getPrincipalName();
+        try {
+            if(!database.hasKey(p)) {
+                LOG.debug("No identity found with the principal {}", p);
+                return null;
+            }
+            
+            database.delete(p);
+            
+            return database.insert(p, identity);
+        }
+        catch(KeyAlreadyExistsException e) {
+            LOG.debug("Identity {} already exists", p);
+            LOG.debug("", e);
+            return null;
+        }
+        catch(Exception e) {
+            LOG.warn("Failed to update the identity {}", p);
+            throw new RuntimeException(e);
+        }
     }
 
     /**
@@ -121,5 +203,26 @@ public class MavibotBackend extends AbstractIdentityBackend {
     @Override
     protected void doDeleteIdentity(String principalName) {
 
+        try {
+            Tuple<String, KrbIdentity> t = database.delete(principalName);
+            if (t == null) {
+                LOG.debug("Identity {} doesn't exist", principalName);
+            }
+        }
+        catch(IOException e) {
+            LOG.warn("Failed to delete the identity {}", principalName);
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void stop() {
+        try {
+            LOG.debug("Closing the database");
+            rm.close();
+        }
+        catch(Exception e) {
+            LOG.warn("Failed to close the database", e);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/d534db85/kerby-backend/mavibot/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java b/kerby-backend/mavibot/src/test/java/org/apache/kerby/KrbIdentitySerializerTest.java
new file mode 100644
index 0000000..227957a
--- /dev/null
+++ b/kerby-backend/mavibot/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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionType;
+import org.junit.Test;
+
+/**
+ * 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
+        }
+    }
+    
+    
+    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/d534db85/kerby-backend/mavibot/src/test/java/org/apache/kerby/MavibotBackendTest.java
----------------------------------------------------------------------
diff --git a/kerby-backend/mavibot/src/test/java/org/apache/kerby/MavibotBackendTest.java b/kerby-backend/mavibot/src/test/java/org/apache/kerby/MavibotBackendTest.java
new file mode 100644
index 0000000..f21600c
--- /dev/null
+++ b/kerby-backend/mavibot/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 static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendTest;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Tests for MavibotBackend.
+ *
+ * @author <a href="mailto:kerby@directory.apache.org">Apache Kerby Project</a>
+ */
+public class MavibotBackendTest extends BackendTest {
+
+    private MavibotBackend backend;
+    
+    private TemporaryFolder tmpFolder = new TemporaryFolder();
+    
+    @Before
+    public void setup() throws Exception {
+        tmpFolder.create();
+        
+        File dbFile = tmpFolder.newFile();
+        backend = new MavibotBackend(dbFile);
+        backend.initialize();
+    }
+    
+    @After
+    public void clean() {
+        backend.stop();
+        tmpFolder.delete();
+    }
+    
+    @Test
+    public void testBackend() {
+        super.testAll(backend);
+    }
+
+    // overriding this cause MavibotBackend doesn't support range search
+    public void testGetIdentities(IdentityBackend backend) {
+        KrbIdentity[] identities = createManyIdentities();
+
+        for (KrbIdentity identity : identities) {
+            backend.addIdentity(identity);
+        }
+
+        // clear the identity cache.
+        backend.release();
+
+        List<String> principals = backend.getIdentities(0, 0);
+        assertThat(principals).hasSize(identities.length);
+        
+        for(KrbIdentity entry : identities) {
+            assertTrue(principals.contains(entry.getPrincipalName()));
+        }
+        
+        for (KrbIdentity identity : identities) {
+            backend.deleteIdentity(identity.getPrincipalName());
+        }
+    }
+}