directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From plusplusjia...@apache.org
Subject [21/27] directory-kerby git commit: DIRKRB-592 Merge kadmin-remote branch to trunk.
Date Thu, 07 Jul 2016 06:42:06 GMT
http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrIntegerTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrIntegerTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrIntegerTest.java
new file mode 100644
index 0000000..9246f12
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrIntegerTest.java
@@ -0,0 +1,80 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.XdrInteger;
+import org.apache.kerby.xdr.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XdrIntegerTest {
+    @Test
+    public void testEncoding() throws IOException {
+        testEncodingWith(0, "0x00 00 00 00");
+        testEncodingWith(1, "0x00 00 00 01");
+        testEncodingWith(2, "0x00 00 00 02");
+        testEncodingWith(127, "0x00 00 00 7F");
+        testEncodingWith(128, "0x00 00 00 80");
+        testEncodingWith(-1, "0xFF FF FF FF");
+        testEncodingWith(-127, "0xFF FF FF 81");
+        testEncodingWith(-255, "0xFF FF FF 01");
+        testEncodingWith(-32768, "0xFF FF 80 00");
+        testEncodingWith(1234567890, "0x49 96 02 D2");
+        testEncodingWith(2147483647, "0x7F FF FF FF");
+        testEncodingWith(-2147483647, "0x80 00 00 01");
+        testEncodingWith(-2147483648, "0x80 00 00 00");
+    }
+
+    private void testEncodingWith(int value, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        XdrInteger aValue = new XdrInteger(value);
+
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+
+    @Test
+    public void testDecoding() throws IOException {
+        testDecodingWith(0, "0x00 00 00 00");
+        testDecodingWith(1, "0x00 00 00 01");
+        testDecodingWith(2, "0x00 00 00 02");
+        testDecodingWith(127, "0x00 00 00 7F");
+        testDecodingWith(128, "0x00 00 00 80");
+        testDecodingWith(-1, "0xFF FF FF FF");
+        testDecodingWith(-127, "0xFF FF FF 81");
+        testDecodingWith(-255, "0xFF FF FF 01");
+        testDecodingWith(-32768, "0xFF FF 80 00");
+        testDecodingWith(1234567890, "0x49 96 02 D2");
+        testDecodingWith(2147483647, "0x7F FF FF FF");
+        testDecodingWith(-2147483647, "0x80 00 00 01");
+        testDecodingWith(-2147483648, "0x80 00 00 00");
+    }
+
+    private void testDecodingWith(int expectedValue, String content) throws IOException {
+        XdrInteger decoded = new XdrInteger();
+
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+        assertThat(decoded.getValue().intValue()).isEqualTo(expectedValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStringTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStringTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStringTest.java
new file mode 100644
index 0000000..8bb30a4
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStringTest.java
@@ -0,0 +1,59 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.XdrString;
+import org.apache.kerby.xdr.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XdrStringTest {
+        @Test
+        public void testEncoding() throws IOException {
+            testEncodingWith("Hello, Kerby!", "0X00 00 00 0D 48 65 6C 6C 6F 2C 20 4B 65 72 62 79 21 00 00 00");
+            testEncodingWith("sillyprog", "0X00 00 00 09 73 69 6C 6C 79 70 72 6F 67 00 00 00");
+            testEncodingWith("(quit)", "0X00 00 00 06 28 71 75 69 74 29 00 00");
+        }
+
+        private void testEncodingWith(String value, String expectedEncoding) throws IOException {
+            byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+            XdrString aValue = new XdrString(value);
+
+            byte[] encodingBytes = aValue.encode();
+            assertThat(encodingBytes).isEqualTo(expected);
+        }
+
+
+        @Test
+        public void testDecoding() throws IOException {
+            testDecodingWith("Hello, Kerby!", "0X00 00 00 0D 48 65 6C 6C 6F 2C 20 4B 65 72 62 79 21 00 00 00");
+            testDecodingWith("sillyprog", "0X00 00 00 09 73 69 6c 6c 79 70 72 6f 67 00 00 00");
+            testDecodingWith("(quit)", "0X00 00 00 06 28 71 75 69 74 29 00 00");
+        }
+
+        private void testDecodingWith(String expectedValue, String content) throws IOException {
+            XdrString decoded = new XdrString();
+            decoded.decode(HexUtil.hex2bytesFriendly(content));
+            assertThat(decoded.getValue()).isEqualTo(expectedValue);
+        }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeInstance.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeInstance.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeInstance.java
new file mode 100644
index 0000000..37c5196
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeInstance.java
@@ -0,0 +1,111 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.AbstractXdrType;
+import org.apache.kerby.xdr.type.XdrBoolean;
+import org.apache.kerby.xdr.type.XdrInteger;
+import org.apache.kerby.xdr.type.XdrString;
+import org.apache.kerby.xdr.type.XdrStructType;
+import org.apache.kerby.xdr.type.XdrType;
+import org.apache.kerby.xdr.type.XdrUnion;
+import org.apache.kerby.xdr.type.XdrUnsignedInteger;
+
+class MyFile {
+    String fileName;
+    UnionFileTypeSwitch fileType;
+    String owner;
+
+    MyFile(String name, UnionFileTypeSwitch fileType, String owner) {
+        this.fileName = name;
+        this.fileType = fileType;
+        this.owner = owner;
+    }
+
+    public String getFileName() {
+        return fileName;
+    }
+
+    public UnionFileTypeSwitch getFileType() {
+        return fileType;
+    }
+
+    public String getOwner() {
+        return owner;
+    }
+
+}
+
+public class XdrStructTypeInstance extends XdrStructType {
+    public XdrStructTypeInstance() {
+        super(XdrDataType.STRUCT);
+    }
+
+    public XdrStructTypeInstance(XdrFieldInfo[] fieldInfos) {
+        super(XdrDataType.STRUCT, fieldInfos);
+    }
+
+    protected  void getStructTypeInstance(final XdrType[] fields, final XdrFieldInfo[] fieldInfos) {
+        for (int i = 0; i < fieldInfos.length; i++) {
+            switch (fieldInfos[i].getDataType()) {
+                case INTEGER:
+                    fields[i] = new XdrInteger((Integer) fieldInfos[i].getValue());
+                    break;
+                case UNSIGNED_INTEGER:
+                    fields[i] = new XdrUnsignedInteger((Long) fieldInfos[i].getValue());
+                    break;
+                case BOOLEAN:
+                    fields[i] = new XdrBoolean((Boolean) fieldInfos[i].getValue());
+                    break;
+                case ENUM:
+                    fields[i] = new FileKindEnumeratedInstance((FileKind) fieldInfos[i].getValue());
+                    break;
+                case UNION:
+                    fields[i] = (XdrUnion) fieldInfos[i].getValue();
+                    break;
+                case STRING:
+                    fields[i] = new XdrString((String) fieldInfos[i].getValue());
+                    break;
+                case STRUCT:
+                    fields[i] = new XdrStructTypeInstance((XdrFieldInfo[]) fieldInfos[i].getValue());
+                default:
+                    fields[i] = null;
+            }
+        }
+
+    }
+
+    @Override
+    protected XdrStructType fieldsToValues(AbstractXdrType[] fields) {
+        XdrFieldInfo[] fieldInfos = {new XdrFieldInfo(0, XdrDataType.STRING, fields[0].getValue()),
+                new XdrFieldInfo(1, XdrDataType.UNION, fields[1].getValue()),
+                new XdrFieldInfo(2, XdrDataType.STRING, fields[2].getValue())};
+        return new XdrStructTypeInstance(fieldInfos);
+    }
+
+    @Override
+    protected AbstractXdrType[] getAllFields() {
+        AbstractXdrType[] fields = new AbstractXdrType[3];
+        fields[0] = new XdrString();
+        fields[1] = new XdrUnionInstance();
+        fields[2] = new XdrString();
+        return fields;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeTest.java
new file mode 100644
index 0000000..c41a20b
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrStructTypeTest.java
@@ -0,0 +1,83 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.XdrStructType;
+import org.apache.kerby.xdr.type.XdrUnion;
+import org.apache.kerby.xdr.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XdrStructTypeTest {
+    @Test
+    public void testEncoding() throws IOException {
+        MyFile file = new MyFile("sillyprog", new UnionFileTypeSwitch(FileKind.EXEC), "john");
+        testEncodingWith(file, "0x00 00 00 09 73 69 6c 6c 79 70 72 6f 67 00 00 00 00 00 00 02 "
+                + "00 00 00 04 6c 69 73 70 00 00 00 04 6a 6f 68 6e");
+    }
+
+    private void testEncodingWith(MyFile value, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        UnionFileTypeSwitch fileType = value.getFileType();
+        XdrFieldInfo[] unionFieldInfo = {new XdrFieldInfo(0, fileType.getFileKind(), fileType.getFileValue()),
+                new XdrFieldInfo(1, fileType.getArmKind(), fileType.getArmValue())};
+        XdrFieldInfo[] fieldInfos = {new XdrFieldInfo(0, XdrDataType.STRING, value.getFileName()),
+                new XdrFieldInfo(1, XdrDataType.UNION, new XdrUnionInstance(unionFieldInfo)),
+                new XdrFieldInfo(2, XdrDataType.STRING, value.getOwner())};
+
+        XdrStructType aValue = new XdrStructTypeInstance(fieldInfos);
+
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+
+    @Test
+    public void testDecoding() throws IOException {
+        MyFile file = new MyFile("sillyprog", new UnionFileTypeSwitch(FileKind.EXEC), "john");
+        testDecodingWith(file, "0x00 00 00 09 73 69 6c 6c 79 70 72 6f 67 00 00 00 00 00 00 02 "
+                + "00 00 00 04 6c 69 73 70 00 00 00 04 6a 6f 68 6e");
+    }
+
+    private void testDecodingWith(MyFile expectedValue, String content) throws IOException {
+        XdrStructType decoded = new XdrStructTypeInstance();
+
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+
+        XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+        assertThat(fieldInfos.length).isEqualTo(3);
+        assertThat(fieldInfos[0].getDataType()).isEqualTo(XdrDataType.STRING);
+        assertThat((String) fieldInfos[0].getValue()).isEqualTo(expectedValue.getFileName());
+
+        assertThat(fieldInfos[1].getDataType()).isEqualTo(XdrDataType.UNION);
+        XdrFieldInfo[] unionFieldInfo = ((XdrUnion) fieldInfos[1].getValue()).getXdrFieldInfos();
+        assertThat(unionFieldInfo[0].getDataType()).isEqualTo(expectedValue.getFileType().getFileKind());
+        assertThat(unionFieldInfo[0].getValue()).isEqualTo(expectedValue.getFileType().getFileValue());
+        assertThat(unionFieldInfo[1].getDataType()).isEqualTo(expectedValue.getFileType().getArmKind());
+        assertThat((String) unionFieldInfo[1].getValue()).isEqualTo(expectedValue.getFileType().getArmValue());
+
+        assertThat(fieldInfos[2].getDataType()).isEqualTo(XdrDataType.STRING);
+        assertThat((String) fieldInfos[2].getValue()).isEqualTo(expectedValue.getOwner());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionInstance.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionInstance.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionInstance.java
new file mode 100644
index 0000000..fbc13b7
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionInstance.java
@@ -0,0 +1,170 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.AbstractXdrType;
+import org.apache.kerby.xdr.type.XdrBoolean;
+import org.apache.kerby.xdr.type.XdrEnumerated;
+import org.apache.kerby.xdr.type.XdrInteger;
+import org.apache.kerby.xdr.type.XdrString;
+import org.apache.kerby.xdr.type.XdrType;
+import org.apache.kerby.xdr.type.XdrUnion;
+import org.apache.kerby.xdr.type.XdrUnsignedInteger;
+
+enum FileKind implements EnumType {
+    TEXT,
+    DATA,
+    EXEC;
+
+    public int getValue() {
+        return ordinal();
+    }
+
+    public String getName() {
+        return name();
+    }
+}
+
+class FileKindEnumeratedInstance extends XdrEnumerated<FileKind> {
+
+    FileKindEnumeratedInstance() {
+        super(null);
+    }
+
+    FileKindEnumeratedInstance(FileKind value) {
+        super(value);
+    }
+    @Override
+    protected EnumType[] getAllEnumValues() {
+        return FileKind.values();
+    }
+
+}
+
+class UnionFileTypeSwitch {
+    FileKind fileKind;
+    Object arm;
+    UnionFileTypeSwitch(FileKind fileKind) {
+        this.fileKind = fileKind;
+        switch (fileKind) {
+            case TEXT:
+                arm = null;
+                break;
+            case DATA:
+                arm = "creator";
+                break;
+            case EXEC:
+                arm = "lisp";
+                break;
+        }
+    }
+
+    XdrDataType getFileKind() {
+        return XdrDataType.ENUM;
+    }
+
+    FileKind getFileValue() {
+        return fileKind;
+    }
+
+    XdrDataType getArmKind() {
+        XdrDataType xdrDataType = XdrDataType.UNKNOWN;
+        switch (fileKind) {
+            case TEXT:
+                xdrDataType = XdrDataType.UNKNOWN;
+                break;
+            case DATA:
+                xdrDataType = XdrDataType.STRING;
+                break;
+            case EXEC:
+                xdrDataType = XdrDataType.STRING;
+                break;
+        }
+        return xdrDataType;
+    }
+
+    Object getArmValue() {
+        return arm;
+    }
+}
+
+public class XdrUnionInstance extends XdrUnion {
+
+    public XdrUnionInstance() {
+        super(XdrDataType.UNION);
+    }
+
+    public XdrUnionInstance(XdrFieldInfo[] fieldInfos) {
+        super(XdrDataType.UNION, fieldInfos);
+    }
+
+
+    @Override
+    protected void getUnionInstance(XdrType[] fields, XdrFieldInfo[] fieldInfos) {
+        switch (fieldInfos[0].getDataType()) {
+            case INTEGER:
+                fields[0] = new XdrInteger((Integer) fieldInfos[0].getValue());
+                break;
+            case UNSIGNED_INTEGER:
+                fields[0] = new XdrUnsignedInteger((Long) fieldInfos[0].getValue());
+                break;
+            case BOOLEAN:
+                fields[0] = new XdrBoolean((Boolean) fieldInfos[0].getValue());
+                break;
+            case ENUM:
+                fields[0] = new FileKindEnumeratedInstance((FileKind) fieldInfos[0].getValue());
+                break;
+            default:
+                throw new RuntimeException("Wrong discriminant type for union: " + fieldInfos[0].getDataType());
+        }
+
+        switch (fieldInfos[1].getDataType()) {
+            case INTEGER:
+                fields[1] = new XdrInteger((Integer) fieldInfos[1].getValue());
+                break;
+            case UNSIGNED_INTEGER:
+                fields[1] = new XdrUnsignedInteger((Long) fieldInfos[1].getValue());
+                break;
+            case BOOLEAN:
+                fields[1] = new XdrBoolean((Boolean) fieldInfos[1].getValue());
+                break;
+            case STRING:
+                fields[1] = new XdrString((String) fieldInfos[1].getValue());
+                break;
+            default:
+                fields[1] = null;
+        }
+    }
+
+    @Override
+    protected XdrUnion fieldsToValues(AbstractXdrType[] fields) {
+        XdrFieldInfo[] fieldInfos = {new XdrFieldInfo(0, XdrDataType.ENUM, fields[0].getValue()),
+                new XdrFieldInfo(1, XdrDataType.STRING, fields[1].getValue())};
+        return new XdrUnionInstance(fieldInfos);
+    }
+
+    @Override
+    protected AbstractXdrType[] getAllFields() {
+        AbstractXdrType[] fields = new AbstractXdrType[2];
+        fields[0] = new FileKindEnumeratedInstance();
+        fields[1] = new XdrString();
+        return fields;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionTest.java
new file mode 100644
index 0000000..e9b9275
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnionTest.java
@@ -0,0 +1,67 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.XdrUnion;
+import org.apache.kerby.xdr.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XdrUnionTest {
+    @Test
+    public void testEncoding() throws IOException {
+        UnionFileTypeSwitch fileType = new UnionFileTypeSwitch(FileKind.EXEC);
+        testEncodingWith(fileType, "0x00 00 00 02 00 00 00 04 6c 69 73 70");
+    }
+
+    private void testEncodingWith(UnionFileTypeSwitch value, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        XdrFieldInfo[] fieldInfos = {new XdrFieldInfo(0, value.getFileKind(), value.getFileValue()),
+                new XdrFieldInfo(1, value.getArmKind(), value.getArmValue())};
+
+        XdrUnion aValue = new XdrUnionInstance(fieldInfos);
+
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+
+    @Test
+    public void testDecoding() throws IOException {
+        UnionFileTypeSwitch fileType = new UnionFileTypeSwitch(FileKind.EXEC);
+        testDecodingWith(fileType, "0x00 00 00 02 00 00 00 04 6c 69 73 70");
+    }
+
+    private void testDecodingWith(UnionFileTypeSwitch expectedValue, String content) throws IOException {
+        XdrUnion decoded = new XdrUnionInstance();
+
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+
+        XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+        assertThat(fieldInfos.length).isEqualTo(2);
+        assertThat(fieldInfos[0].getDataType()).isEqualTo(expectedValue.getFileKind());
+        assertThat((FileKind) fieldInfos[0].getValue()).isEqualTo(expectedValue.getFileValue());
+        assertThat(fieldInfos[1].getDataType()).isEqualTo(expectedValue.getArmKind());
+        assertThat((String) fieldInfos[1].getValue()).isEqualTo(expectedValue.getArmValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnsignedIntegerTest.java
----------------------------------------------------------------------
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnsignedIntegerTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnsignedIntegerTest.java
new file mode 100644
index 0000000..118f094
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrUnsignedIntegerTest.java
@@ -0,0 +1,69 @@
+/**
+ *  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.xdr;
+
+import org.apache.kerby.xdr.type.XdrUnsignedInteger;
+import org.apache.kerby.xdr.util.HexUtil;
+import org.junit.Test;
+
+import java.io.IOException;
+
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class XdrUnsignedIntegerTest {
+    @Test
+    public void testEncoding() throws IOException {
+        testEncodingWith("0", "0x00 00 00 00");
+        testEncodingWith("1", "0x00 00 00 01");
+        testEncodingWith("2", "0x00 00 00 02");
+        testEncodingWith("1234567890", "0x49 96 02 D2");
+        testEncodingWith("2147483647", "0x7F FF FF FF");
+        testEncodingWith("2147483648", "0x80 00 00 00");
+        testEncodingWith("4294967295", "0xFF FF FF FF");
+    }
+
+    private void testEncodingWith(String value, String expectedEncoding) throws IOException {
+        byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+        XdrUnsignedInteger aValue = new XdrUnsignedInteger(value);
+
+        byte[] encodingBytes = aValue.encode();
+        assertThat(encodingBytes).isEqualTo(expected);
+    }
+
+
+    @Test
+    public void testDecoding() throws IOException {
+        testDecodingWith("0", "0x00 00 00 00");
+        testDecodingWith("1", "0x00 00 00 01");
+        testDecodingWith("2", "0x00 00 00 02");
+        testDecodingWith("1234567890", "0x49 96 02 D2");
+        testDecodingWith("2147483647", "0x7F FF FF FF");
+        testDecodingWith("2147483648", "0x80 00 00 00");
+        testDecodingWith("4294967295", "0xFF FF FF FF");
+    }
+
+    private void testDecodingWith(String expectedValue, String content) throws IOException {
+        XdrUnsignedInteger decoded = new XdrUnsignedInteger();
+
+        decoded.decode(HexUtil.hex2bytesFriendly(content));
+        assertThat(decoded.getValue().toString()).isEqualTo(expectedValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-common/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-common/pom.xml b/kerby-common/pom.xml
index 309fcd7..e2e679b 100644
--- a/kerby-common/pom.xml
+++ b/kerby-common/pom.xml
@@ -29,5 +29,6 @@
     <module>kerby-asn1</module>
     <module>kerby-config</module>
     <module>kerby-util</module>
+    <module>kerby-xdr</module>
   </modules>
 </project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/bin/admin-server.cmd
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/bin/admin-server.cmd b/kerby-dist/kdc-dist/bin/admin-server.cmd
new file mode 100644
index 0000000..091773f
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/admin-server.cmd
@@ -0,0 +1,32 @@
+@echo off
+@rem  Licensed to the Apache Software Foundation (ASF) under one
+@rem  or more contributor license agreements.  See the NOTICE file
+@rem  distributed with this work for additional information
+@rem  regarding copyright ownership.  The ASF licenses this file
+@rem  to you under the Apache License, Version 2.0 (the
+@rem  "License"); you may not use this file except in compliance
+@rem  with the License.  You may obtain a copy of the License at
+@rem
+@rem    http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem  Unless required by applicable law or agreed to in writing,
+@rem  software distributed under the License is distributed on an
+@rem  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem  KIND, either express or implied.  See the License for the
+@rem  specific language governing permissions and limitations
+@rem  under the License.
+@rem
+
+set DEBUG=
+set args=%*
+for %%a in (%*) do (
+  if -D == %%a (
+    set DEBUG=-Xdebug -Xrunjdwp:transport=dt_socket,address=8008,server=y,suspend=n
+    set args=%args:-D=%
+  )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=admin-server ^
+org.apache.kerby.kerberos.kerb.admin.server.KerbyAdminServer %args%

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/bin/admin-server.sh
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/bin/admin-server.sh b/kerby-dist/kdc-dist/bin/admin-server.sh
new file mode 100644
index 0000000..fb455f2
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/admin-server.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# 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.
+
+DEBUG=
+args=
+for var in $*; do
+  if [ X"$var" = X"-D" ]; then
+    DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,address=8008,server=y,suspend=n"
+  else
+    args="$args $var"
+  fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=admin-server \
+org.apache.kerby.kerberos.kerb.admin.server.KerbyAdminServer $args
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/bin/remote-admin-client.cmd
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/bin/remote-admin-client.cmd b/kerby-dist/kdc-dist/bin/remote-admin-client.cmd
new file mode 100644
index 0000000..d8fc483
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/remote-admin-client.cmd
@@ -0,0 +1,32 @@
+@echo off
+@rem  Licensed to the Apache Software Foundation (ASF) under one
+@rem  or more contributor license agreements.  See the NOTICE file
+@rem  distributed with this work for additional information
+@rem  regarding copyright ownership.  The ASF licenses this file
+@rem  to you under the Apache License, Version 2.0 (the
+@rem  "License"); you may not use this file except in compliance
+@rem  with the License.  You may obtain a copy of the License at
+@rem
+@rem    http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem  Unless required by applicable law or agreed to in writing,
+@rem  software distributed under the License is distributed on an
+@rem  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem  KIND, either express or implied.  See the License for the
+@rem  specific language governing permissions and limitations
+@rem  under the License.
+@rem
+
+set DEBUG=
+set args=%*
+for %%a in (%*) do (
+  if -D == %%a (
+    set DEBUG=-Xdebug -Xrunjdwp:transport=dt_socket,address=8009,server=y,suspend=n
+    set args=%args:-D=%
+  )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=remote-admin-client ^
+org.apache.kerby.kerberos.kerb.admin.RemoteAdminClientTool %args%
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/bin/remote-admin-client.sh
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/bin/remote-admin-client.sh b/kerby-dist/kdc-dist/bin/remote-admin-client.sh
new file mode 100644
index 0000000..21b7848
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/remote-admin-client.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# 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.
+
+DEBUG=
+args=
+for var in $*; do
+  if [ X"$var" = X"-D" ]; then
+    DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,address=8009,server=y,suspend=n"
+  else
+    args="$args $var"
+  fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=remote-admin-client \
+org.apache.kerby.kerberos.kerb.admin.RemoteAdminClientTool $args
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/conf/adminClient.conf
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/conf/adminClient.conf b/kerby-dist/kdc-dist/conf/adminClient.conf
new file mode 100644
index 0000000..7c6909b
--- /dev/null
+++ b/kerby-dist/kdc-dist/conf/adminClient.conf
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+[libdefaults]
+default_realm = EXAMPLE.COM
+admin_port = 65417
+keytab_file = admin.keytab
+protocol = adminprotocol
+server_name = localhost

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/conf/adminServer.conf
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/conf/adminServer.conf b/kerby-dist/kdc-dist/conf/adminServer.conf
new file mode 100644
index 0000000..ecb5bca
--- /dev/null
+++ b/kerby-dist/kdc-dist/conf/adminServer.conf
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+[libdefaults]
+default_realm = EXAMPLE.COM
+admin_port = 65417
+keytab_file = protocol.keytab
+protocol = adminprotocol
+server_name = localhost

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-dist/kdc-dist/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-dist/kdc-dist/pom.xml b/kerby-dist/kdc-dist/pom.xml
index 71c5f25..da3a2e1 100644
--- a/kerby-dist/kdc-dist/pom.xml
+++ b/kerby-dist/kdc-dist/pom.xml
@@ -35,6 +35,16 @@
     </dependency>
     <dependency>
       <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-admin-server</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-admin</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
       <artifactId>kerby-asn1</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kdc/src/main/java/org/apache/kerby/kerberos/kdc/KerbyKdcServer.java
----------------------------------------------------------------------
diff --git a/kerby-kdc/src/main/java/org/apache/kerby/kerberos/kdc/KerbyKdcServer.java b/kerby-kdc/src/main/java/org/apache/kerby/kerberos/kdc/KerbyKdcServer.java
index 0bbe7b7..79cc46a 100644
--- a/kerby-kdc/src/main/java/org/apache/kerby/kerberos/kdc/KerbyKdcServer.java
+++ b/kerby-kdc/src/main/java/org/apache/kerby/kerberos/kdc/KerbyKdcServer.java
@@ -21,8 +21,8 @@ package org.apache.kerby.kerberos.kdc;
 
 import org.apache.kerby.kerberos.kdc.impl.NettyKdcServerImpl;
 import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadminImpl;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadminImpl;
 import org.apache.kerby.kerberos.kerb.server.KdcServer;
 import org.apache.kerby.util.OSUtil;
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/pom.xml
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/pom.xml b/kerby-kerb/kerb-admin-server/pom.xml
new file mode 100644
index 0000000..546f6da
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/pom.xml
@@ -0,0 +1,56 @@
+<?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-kerb</artifactId>
+    <version>1.0.0-RC3-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>kerb-admin-server</artifactId>
+
+  <name>Kerby-kerb Admin Server</name>
+  <description>Kerby-kerb Admin Server</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-util</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-admin</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/KerbyAdminServer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/KerbyAdminServer.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/KerbyAdminServer.java
new file mode 100644
index 0000000..50e59e3
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/KerbyAdminServer.java
@@ -0,0 +1,80 @@
+/**
+ *  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.admin.server;
+
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.Krb5Conf;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServer;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.util.OSUtil;
+
+import java.io.File;
+import java.io.IOException;
+
+public class KerbyAdminServer {
+    private static final String USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\admin-server.cmd" : "Usage: sh bin/admin-server.sh")
+        + " <conf-file>\n"
+        + "\tExample:\n"
+        + "\t\t"
+        + (OSUtil.isWindows()
+        ? "bin\\admin-server.cmd" : "sh bin/admin-server.sh")
+        + " conf\n";
+
+    public static void main(String[] args) throws Exception {
+
+        if (args.length != 1) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+
+        String confDirPath = args[0];
+        AdminServer adminServer = new AdminServer(new File(confDirPath));
+        AdminServerConfig adminServerConfig = adminServer.getAdminServerConfig();
+
+        adminServer.setAdminHost(adminServerConfig.getAdminHost());
+        adminServer.setAllowTcp(true);
+        adminServer.setAllowUdp(false);
+        adminServer.setAdminServerPort(adminServerConfig.getAdminPort());
+
+        KdcConfig kdcConfig = KdcUtil.getKdcConfig(new File(confDirPath));
+        if (kdcConfig == null) {
+            kdcConfig = new KdcConfig();
+        }
+        try {
+            Krb5Conf krb5Conf = new Krb5Conf(new File(confDirPath), kdcConfig);
+            krb5Conf.initKrb5conf();
+        } catch (IOException e) {
+            throw new KrbException("Failed to make krb5.conf", e);
+        }
+
+        try {
+            adminServer.init();
+        } catch (KrbException e) {
+            System.err.println("Errors occurred when start admin server:  " + e.getMessage());
+            System.exit(2);
+        }
+        adminServer.start();
+        System.out.println("Admin server started!");
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServer.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServer.java
new file mode 100644
index 0000000..659750a
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServer.java
@@ -0,0 +1,266 @@
+/**
+ *  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.admin.server.kadmin;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.impl.DefaultInternalAdminServerImpl;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.impl.InternalAdminServer;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+
+import java.io.File;
+
+/**
+ * The implemented Kerberos remote admin server API.
+ * We add the KdcConfig as a member variable to AdminServer,
+ * In order to make it easy to use LocalKadminImpl.
+ * The Kdc Config of corresponding KDC can be read from ConfDir.
+ */
+public class AdminServer {
+    private final AdminServerConfig adminServerConfig;
+    private final BackendConfig backendConfig;
+    private final KdcConfig kdcConfig;
+    private final AdminServerSetting adminServerSetting;
+    private final KOptions startupOptions;
+
+    private InternalAdminServer innerAdminServer;
+
+    /**
+     * Constructor passing adminServerConfig, kdcConfig and backendConfig.
+     * @param adminServerConfig The admin server config
+     * @param backendConfig The backend config
+     * @param kdcConfig The kdc config
+     * @throws KrbException e
+     */
+    public AdminServer(AdminServerConfig adminServerConfig,
+                     BackendConfig backendConfig, KdcConfig kdcConfig) throws KrbException {
+        this.adminServerConfig = adminServerConfig;
+        this.kdcConfig = kdcConfig;
+        this.backendConfig = backendConfig;
+        startupOptions = new KOptions();
+        adminServerSetting = new AdminServerSetting(startupOptions,
+            adminServerConfig, kdcConfig, backendConfig);
+    }
+
+    /**
+     * Constructor given confDir where 'adminServer.conf', 'kdc.conf' and
+     * 'backend.conf' should be available.
+     * adminServer.conf that contains adminServer related items.
+     * kdc.conf, that contains kdc related items.
+     * backend.conf, that contains identity backend related items.
+     *
+     * @param confDir The conf dir
+     * @throws KrbException e
+     */
+    public AdminServer(File confDir) throws KrbException {
+        AdminServerConfig tmpAdminServerConfig =
+            AdminServerUtil.getAdminServerConfig(confDir);
+        if (tmpAdminServerConfig == null) {
+            tmpAdminServerConfig = new AdminServerConfig();
+        }
+        this.adminServerConfig = tmpAdminServerConfig;
+
+        KdcConfig tmpKdcConfig = AdminServerUtil.getKdcConfig(confDir);
+        if (tmpKdcConfig == null) {
+            tmpKdcConfig = new KdcConfig();
+        }
+        this.kdcConfig = tmpKdcConfig;
+
+        BackendConfig tmpBackendConfig = AdminServerUtil.getBackendConfig(confDir);
+        if (tmpBackendConfig == null) {
+            tmpBackendConfig = new BackendConfig();
+        }
+        tmpBackendConfig.setConfDir(confDir);
+        this.backendConfig = tmpBackendConfig;
+
+        startupOptions = new KOptions();
+        adminServerSetting = new AdminServerSetting(startupOptions,
+            adminServerConfig, kdcConfig, backendConfig);
+    }
+
+    /**
+     * Default constructor.
+     */
+    public AdminServer() {
+        adminServerConfig = new AdminServerConfig();
+        backendConfig = new BackendConfig();
+        kdcConfig = new KdcConfig();
+        startupOptions = new KOptions();
+        adminServerSetting = new AdminServerSetting(startupOptions,
+            adminServerConfig, kdcConfig, backendConfig);
+    }
+
+    /**
+     * Set Admin realm for ticket request
+     * @param realm The kdc realm
+     */
+    public void setAdminServerRealm(String realm) {
+        startupOptions.add(AdminServerOption.ADMIN_REALM, realm);
+    }
+
+    /**
+     * Set Admin host.
+     * @param adminHost The kdc host
+     */
+    public void setAdminHost(String adminHost) {
+        startupOptions.add(AdminServerOption.ADMIN_HOST, adminHost);
+    }
+
+    /**
+     * Set Admin port.
+     * @param adminPort The admin port
+     */
+    public void setAdminServerPort(int adminPort) {
+        startupOptions.add(AdminServerOption.ADMIN_PORT, adminPort);
+    }
+
+    /**
+     * Set Admin tcp port.
+     * @param adminTcpPort The admin tcp port
+     */
+    public void setAdminTcpPort(int adminTcpPort) {
+        startupOptions.add(AdminServerOption.ADMIN_TCP_PORT, adminTcpPort);
+    }
+
+    /**
+     * Set to allow UDP or not.
+     * @param allowUdp true if allow udp
+     */
+    public void setAllowUdp(boolean allowUdp) {
+        startupOptions.add(AdminServerOption.ALLOW_UDP, allowUdp);
+    }
+
+    /**
+     * Set to allow TCP or not.
+     * @param allowTcp true if allow tcp
+     */
+    public void setAllowTcp(boolean allowTcp) {
+        startupOptions.add(AdminServerOption.ALLOW_TCP, allowTcp);
+    }
+    /**
+     * Set Admin udp port. Only makes sense when allowUdp is set.
+     * @param adminUdpPort The admin udp port
+     */
+    public void setAdminUdpPort(int adminUdpPort) {
+        startupOptions.add(AdminServerOption.ADMIN_UDP_PORT, adminUdpPort);
+    }
+
+    /**
+     * Set runtime folder.
+     * @param workDir The work dir
+     */
+    public void setWorkDir(File workDir) {
+        startupOptions.add(AdminServerOption.WORK_DIR, workDir);
+    }
+
+    /**
+     * Allow to debug so have more logs.
+     */
+    public void enableDebug() {
+        startupOptions.add(AdminServerOption.ENABLE_DEBUG);
+    }
+
+    /**
+     * Allow to hook customized admin implementation.
+     *
+     * @param innerAdminServerImpl The inner admin implementation
+     */
+    public void setInnerAdminServerImpl(InternalAdminServer innerAdminServerImpl) {
+        startupOptions.add(AdminServerOption.INNER_ADMIN_IMPL, innerAdminServerImpl);
+    }
+
+    /**
+     * Get Admin setting from startup options and configs.
+     * @return setting
+     */
+    public AdminServerSetting getAdminServerSetting() {
+        return adminServerSetting;
+    }
+
+    /**
+     * Get the Admin config.
+     * @return AdminServerConfig
+     */
+    public AdminServerConfig getAdminServerConfig() {
+        return adminServerConfig;
+    }
+
+    /**
+     * Get backend config.
+     *
+     * @return backend configuration
+     */
+    public BackendConfig getBackendConfig() {
+        return backendConfig;
+    }
+
+    /**
+     * Get identity service.
+     * @return IdentityService
+     */
+    public IdentityBackend getIdentityService() {
+        if (innerAdminServer == null) {
+            throw new RuntimeException("Not init yet");
+        }
+        return innerAdminServer.getIdentityBackend();
+    }
+
+    /**
+     * Initialize.
+     *
+     * @throws KrbException e.
+     */
+    public void init() throws KrbException {
+        if (startupOptions.contains(AdminServerOption.INNER_ADMIN_IMPL)) {
+            innerAdminServer = (InternalAdminServer) startupOptions.getOptionValue(
+                AdminServerOption.INNER_ADMIN_IMPL);
+        } else {
+            innerAdminServer =
+                new DefaultInternalAdminServerImpl(adminServerSetting);
+        }
+
+        innerAdminServer.init();
+    }
+
+    /**
+     * Start the Admin admin.
+     *
+     * @throws KrbException e.
+     */
+    public void start() throws KrbException {
+        if (innerAdminServer == null) {
+            throw new RuntimeException("Not init yet");
+        }
+        innerAdminServer.start();
+    }
+
+    /**
+     * Stop the Admin admin.
+     *
+     * @throws KrbException e.
+     */
+    public void stop() throws KrbException {
+        if (innerAdminServer != null) {
+            innerAdminServer.stop();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfig.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfig.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfig.java
new file mode 100644
index 0000000..97e0904
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfig.java
@@ -0,0 +1,105 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.kerberos.kerb.admin.server.kadmin;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb admin server side configuration API.
+ */
+public class AdminServerConfig extends Krb5Conf {
+    private static final String KDCDEFAULT = "kdcdefaults";
+
+    public boolean enableDebug() {
+        return getBoolean(AdminServerConfigKey.KRB_DEBUG, true, KDCDEFAULT);
+    }
+
+    public String getAdminServiceName() {
+        return getString(AdminServerConfigKey.ADMIN_SERVICE_NAME, true, KDCDEFAULT);
+    }
+
+    public String getAdminHost() {
+        return getString(AdminServerConfigKey.ADMIN_HOST, true, KDCDEFAULT);
+    }
+
+    public int getAdminPort() {
+        Integer kdcPort = getInt(AdminServerConfigKey.ADMIN_PORT, true, KDCDEFAULT);
+        if (kdcPort != null && kdcPort > 0) {
+            return kdcPort.intValue();
+        }
+        return -1;
+    }
+
+    public int getAdminTcpPort() {
+        Integer kdcTcpPort = getInt(AdminServerConfigKey.ADMIN_TCP_PORT, true, KDCDEFAULT);
+        if (kdcTcpPort != null && kdcTcpPort > 0) {
+            return kdcTcpPort.intValue();
+        }
+        return getAdminPort();
+    }
+
+    /**
+     * Is to allow TCP for KDC
+     * @return true to allow TCP, false otherwise
+     */
+    public Boolean allowTcp() {
+        return getBoolean(AdminServerConfigKey.ADMIN_ALLOW_TCP, true, KDCDEFAULT)
+                || getInt(AdminServerConfigKey.ADMIN_TCP_PORT, true, KDCDEFAULT) != null
+            || getInt(AdminServerConfigKey.ADMIN_PORT, false, KDCDEFAULT) != null;
+    }
+
+    /**
+     * Is to allow UDP for KDC
+     * @return true to allow UDP, false otherwise
+     */
+    public Boolean allowUdp() {
+        return getBoolean(AdminServerConfigKey.ADMIN_ALLOW_UDP, true, KDCDEFAULT)
+                || getInt(AdminServerConfigKey.ADMIN_UDP_PORT, true, KDCDEFAULT) != null
+            || getInt(AdminServerConfigKey.ADMIN_PORT, false, KDCDEFAULT) != null;
+    }
+
+    public int getAdminUdpPort() {
+        Integer kdcUdpPort = getInt(AdminServerConfigKey.ADMIN_UDP_PORT, true, KDCDEFAULT);
+        if (kdcUdpPort != null && kdcUdpPort > 0) {
+            return kdcUdpPort.intValue();
+        }
+        return getAdminPort();
+    }
+
+    public String getAdminRealm() {
+        return getString(AdminServerConfigKey.ADMIN_REALM, true, KDCDEFAULT);
+    }
+
+    public String getAdminDomain() {
+        return getString(AdminServerConfigKey.ADMIN_DOMAIN, true, KDCDEFAULT);
+    }
+
+    public String getKeyTabFile() {
+        return getString(AdminServerConfigKey.KEYTAB_FILE, true, KDCDEFAULT);
+    }
+
+    public String getProtocol() {
+        return getString(AdminServerConfigKey.PROTOCOL, true, KDCDEFAULT);
+    }
+
+    public String getServerName() {
+        return getString(AdminServerConfigKey.SERVER_NAME, true, KDCDEFAULT);
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfigKey.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfigKey.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfigKey.java
new file mode 100644
index 0000000..6b71042
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerConfigKey.java
@@ -0,0 +1,59 @@
+/**
+ *  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.admin.server.kadmin;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum AdminServerConfigKey implements ConfigKey {
+    KRB_DEBUG(true),
+    ADMIN_SERVICE_NAME("Kadmin-Server"),
+    KDC_IDENTITY_BACKEND,
+    ADMIN_HOST("localhost"),
+    ADMIN_PORT,
+    ADMIN_ALLOW_TCP(true),
+    ADMIN_ALLOW_UDP(true),
+    ADMIN_UDP_PORT,
+    ADMIN_TCP_PORT,
+    ADMIN_DOMAIN("example.com"),
+    ADMIN_REALM("EXAMPLE.COM"),
+    KEYTAB_FILE,
+    PROTOCOL,
+    SERVER_NAME("localhost");
+
+    private Object defaultValue;
+
+    AdminServerConfigKey() {
+        this.defaultValue = null;
+    }
+
+    AdminServerConfigKey(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public String getPropertyKey() {
+        return name().toLowerCase();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return this.defaultValue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerContext.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerContext.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerContext.java
new file mode 100644
index 0000000..e057872
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerContext.java
@@ -0,0 +1,52 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.kerberos.kerb.admin.server.kadmin;
+
+import org.apache.kerby.kerberos.kerb.identity.IdentityService;
+
+public class AdminServerContext {
+    private final AdminServerSetting adminServerSetting;
+
+    private IdentityService identityService;
+
+    public AdminServerContext(AdminServerSetting adminServerSetting) {
+        this.adminServerSetting = adminServerSetting;
+    }
+
+    public AdminServerSetting getAdminServerSetting() {
+        return adminServerSetting;
+    }
+
+    public AdminServerConfig getConfig() {
+        return adminServerSetting.getAdminServerConfig();
+    }
+
+    public void setIdentityService(IdentityService identityService) {
+        this.identityService = identityService;
+    }
+
+    public IdentityService getIdentityService() {
+        return identityService;
+    }
+
+    public String getAdminRealm() {
+        return adminServerSetting.getAdminRealm();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerHandler.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerHandler.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerHandler.java
new file mode 100644
index 0000000..5b85d96
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerHandler.java
@@ -0,0 +1,238 @@
+/**
+ *  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.admin.server.kadmin;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadminImpl;
+import org.apache.kerby.kerberos.kerb.admin.message.AddPrincipalRep;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessage;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessageCode;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessageType;
+import org.apache.kerby.kerberos.kerb.admin.message.DeletePrincipalRep;
+import org.apache.kerby.kerberos.kerb.admin.message.GetprincsRep;
+import org.apache.kerby.kerberos.kerb.admin.message.KadminCode;
+import org.apache.kerby.kerberos.kerb.admin.message.RenamePrincipalRep;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+import org.apache.kerby.xdr.type.XdrStructType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * admin server handler to process client acmin requests.
+ */
+public class AdminServerHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(AdminServerHandler.class);
+    private final AdminServerContext adminServerContext;
+
+    /**
+     * Constructor with admin server context.
+     *
+     * @param adminServerContext admin admin server context
+     */
+    public AdminServerHandler(AdminServerContext adminServerContext) {
+        this.adminServerContext = adminServerContext;
+        LOG.info("Admin realm: " + this.adminServerContext.getAdminRealm());
+    }
+
+    /**
+     * Process the client request message.
+     *
+     * @throws KrbException e
+     * @param receivedMessage The client request message
+     * @param remoteAddress Address from remote side
+     * @return The response message
+     */
+    public ByteBuffer handleMessage(ByteBuffer receivedMessage,
+                                    InetAddress remoteAddress) throws KrbException, IOException {
+        XdrStructType decoded = new AdminMessageCode();
+        decoded.decode(receivedMessage);
+        XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+        AdminMessageType type = (AdminMessageType) fieldInfos[0].getValue();
+
+        /**Create LocalKadmin here*/
+        LocalKadmin localKadmin = new LocalKadminImpl(adminServerContext.getAdminServerSetting());
+        ByteBuffer responseMessage = null;
+
+        switch (type) {
+            case ADD_PRINCIPAL_REQ:
+                System.out.println("message type: add principal req");
+                responseMessage = handleAddPrincipalReq(localKadmin, fieldInfos);
+                break;
+            case DELETE_PRINCIPAL_REQ:
+                System.out.println("message type: delete principal req");
+                responseMessage = handleDeletePrincipalReq(localKadmin, fieldInfos);
+                break;
+            case RENAME_PRINCIPAL_REQ:
+                System.out.println("message type: rename principal req");
+                responseMessage = handleRenamePrincipalReq(localKadmin, fieldInfos);
+                break;
+            case GET_PRINCS_REQ:
+                System.out.println("message type getPrincs req");
+                responseMessage = handleGetprincsReq(localKadmin, fieldInfos);
+                break;
+            default:
+                throw new KrbException("AdminMessageType error, can not handle it.");
+        }
+        return responseMessage;
+
+    }
+
+    private ByteBuffer handleAddPrincipalReq(LocalKadmin localKadmin, XdrFieldInfo[] fieldInfos) throws IOException {
+        String principal = (String) fieldInfos[2].getValue();
+        int paramNum = (int) fieldInfos[1].getValue();
+
+        if (paramNum == 1) {
+            /** Add principal with only principal name*/
+            LOG.info("handle nokey principal " + principal);
+            String[] temp = principal.split("@");
+            try {
+                localKadmin.addPrincipal(temp[0]);
+            } catch (KrbException e) {
+                String error = "principal already exist!";
+                LOG.error(error);
+                System.err.println(error);
+                ByteBuffer response = infoPackageTool(error, "addPrincipal");
+                return response;
+            }
+        } else if (paramNum == 2 && fieldInfos[3].getDataType() == XdrDataType.STRING) {
+            /** Add principal with password*/
+            LOG.info("handle principal with password " + principal);
+            String[] temp = principal.split("@");
+            String password = (String) fieldInfos[3].getValue();
+            try {
+                localKadmin.addPrincipal(temp[0], password);
+            } catch (KrbException e) {
+                String error = "principal already exist.\n"
+                        + "Choose update password instead of add principal";
+                LOG.error(error);
+                ByteBuffer response = infoPackageTool(error, "addPrincipal");
+                return response;
+            }
+        }
+        String message = "add principal of " + principal;
+        LOG.info(message);
+        ByteBuffer responseMessage = infoPackageTool(message, "addPrincipal");
+        return responseMessage;
+    }
+
+    private ByteBuffer handleDeletePrincipalReq(LocalKadmin localKadmin, XdrFieldInfo[] fieldInfos) throws IOException {
+        /** message structure: msg_type, para_num(always equals 1), principal_name*/
+        String principal = (String) fieldInfos[2].getValue();
+        String[] temp = principal.split("@");
+        try {
+            localKadmin.deletePrincipal(temp[0]);
+        } catch (KrbException e) {
+            String error = "no such principal exist!";
+            LOG.error(error);
+            ByteBuffer response = infoPackageTool(error, "deletePrincipal");
+            return response;
+        }
+        String message = "delete principal of " + principal;
+        LOG.info(message);
+        ByteBuffer responseMessage = infoPackageTool(message, "deletePrincipal");
+        return responseMessage;
+    }
+
+    private ByteBuffer handleRenamePrincipalReq(LocalKadmin localKadmin, XdrFieldInfo[] fieldInfos) throws IOException {
+        /** message structure: msg_type, para_num(always equals 2), old name, new name*/
+
+        String[] oldPrincipalName = ((String) fieldInfos[2].getValue()).split("@");
+        String[] newPrincipalName = ((String) fieldInfos[3].getValue()).split("@");
+        try {
+            localKadmin.renamePrincipal(oldPrincipalName[0], newPrincipalName[0]);
+        } catch (KrbException e) {
+            String error = "the old principal name does not exist, or the new principal name"
+                    + " already exists, rename failed.";
+            System.err.println(error);
+            ByteBuffer response = infoPackageTool(error, "renamePrincipal");
+            return response;
+        }
+
+        String message = "rename " + oldPrincipalName[0] + " to " + newPrincipalName[0];
+        ByteBuffer responseMessage = infoPackageTool(message, "renamePrincipal");
+        return responseMessage;
+    }
+
+    private ByteBuffer handleGetprincsReq(LocalKadmin localKadmin, XdrFieldInfo[] fieldInfos) throws IOException {
+        String globString = ((String) fieldInfos[2].getValue());
+        List<String> princsList = null;
+
+        try {
+            if (globString == null || globString.isEmpty()) {
+                princsList = localKadmin.getPrincipals();
+            } else {
+                princsList = localKadmin.getPrincipals(globString);
+            }
+            ByteBuffer responseMessage = infoPackageTool(listToString(princsList), "getPrincs");
+            return responseMessage;
+        } catch (KrbException e) {
+            String error = "principal do not exist.";
+            ByteBuffer responseError = infoPackageTool(error, "getPrincs");
+            return responseError;
+        }
+    }
+
+    private ByteBuffer infoPackageTool(String message, String dealType) throws IOException {
+        AdminMessage adminMessage = null;
+        XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[3];
+
+        if ("getPrincs".equals(dealType)) {
+            adminMessage = new GetprincsRep();
+            xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.GET_PRINCS_REP);
+        } else if ("renamePrincipal".equals(dealType)) {
+            adminMessage = new RenamePrincipalRep();
+            xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.RENAME_PRINCIPAL_REP);
+        } else if ("deletePrincipal".equals(dealType)) {
+            adminMessage = new DeletePrincipalRep();
+            xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.DELETE_PRINCIPAL_REP);
+        } else if ("addPrincipal".equals(dealType)) {
+            adminMessage = new AddPrincipalRep();
+            xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.ADD_PRINCIPAL_REP);
+        }
+
+        xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, 1);
+        xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, message);
+
+        AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
+        adminMessage.setMessageBuffer(ByteBuffer.wrap(value.encode()));
+
+        ByteBuffer responseMessage = KadminCode.encodeMessage(adminMessage);
+        return responseMessage;
+    }
+
+    private String listToString(List<String> list) {
+        if (list.size() <= 0) {
+            return null;
+        }
+        //Both speed and safety,so use StringBuffer
+        StringBuffer result = new StringBuffer();
+        for (int i = 0; i < list.size(); i++) {
+            result.append(list.get(i)).append(" ");
+        }
+        return result.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerOption.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerOption.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerOption.java
new file mode 100644
index 0000000..aa87a7c
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerOption.java
@@ -0,0 +1,52 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.kerberos.kerb.admin.server.kadmin;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * KDC admin startup options
+ */
+public enum AdminServerOption implements KOption {
+    NONE(null),
+    INNER_ADMIN_IMPL(new KOptionInfo("inner KDC impl", "inner KDC impl", KOptionType.OBJ)),
+    ADMIN_REALM(new KOptionInfo("kdc realm", "kdc realm", KOptionType.STR)),
+    ADMIN_HOST(new KOptionInfo("kdc host", "kdc host", KOptionType.STR)),
+    ADMIN_PORT(new KOptionInfo("kdc port", "kdc port", KOptionType.INT)),
+    ALLOW_TCP(new KOptionInfo("allow tcp", "allow tcp", KOptionType.BOOL)),
+    ADMIN_TCP_PORT(new KOptionInfo("kdc tcp port", "kdc tcp port", KOptionType.INT)),
+    ALLOW_UDP(new KOptionInfo("allow udp", "allow udp", KOptionType.BOOL)),
+    ADMIN_UDP_PORT(new KOptionInfo("kdc udp port", "kdc udp port", KOptionType.INT)),
+    WORK_DIR(new KOptionInfo("work dir", "work dir", KOptionType.DIR)),
+    ENABLE_DEBUG(new KOptionInfo("enable debug", "enable debug", KOptionType.BOOL));
+
+    private final KOptionInfo optionInfo;
+
+    AdminServerOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/9f628e5a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerSetting.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerSetting.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerSetting.java
new file mode 100644
index 0000000..a8dba48
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerSetting.java
@@ -0,0 +1,212 @@
+/**
+ *  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.admin.server.kadmin;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.ServerSetting;
+
+/**
+ * Admin Server setting that combines startup options and admin config.
+ */
+public class AdminServerSetting implements ServerSetting {
+    private final KOptions startupOptions;
+    private final AdminServerConfig adminServerConfig;
+    private final KdcConfig kdcConfig;
+    private final BackendConfig backendConfig;
+
+    /**
+     * AdminServerSetting constructor
+     * @param startupOptions startup options
+     * @param adminServerConfig admin configuration
+     * @param kdcConfig kdc configuration
+     * @param backendConfig backend configuration
+     */
+    public AdminServerSetting(KOptions startupOptions,
+                              AdminServerConfig adminServerConfig,
+                              KdcConfig kdcConfig,
+                              BackendConfig backendConfig) {
+        this.startupOptions = startupOptions;
+        this.adminServerConfig = adminServerConfig;
+        this.kdcConfig = kdcConfig;
+        this.backendConfig = backendConfig;
+    }
+
+    public AdminServerSetting(AdminServerConfig adminServerConfig, 
+                              BackendConfig backendConfig, KdcConfig kdcConfig) {
+        this(new KOptions(), adminServerConfig, kdcConfig, backendConfig);
+    }
+
+    /**
+     * Get the Admin Server config.
+     * @return admin configuration
+     */
+    public AdminServerConfig getAdminServerConfig() {
+        return adminServerConfig;
+    }
+
+    /**
+     * Get the realm of KDC of Admin Server.
+     * @return the realm of KDC
+     */
+    @Override
+    public String getKdcRealm() {
+         return kdcConfig.getKdcRealm();
+    }
+
+    /**
+     * Get the KDC config of Admin server.
+     * @return the KDC configuration
+     */
+    @Override
+    public KdcConfig getKdcConfig() {
+        return kdcConfig;
+    }
+
+    /**
+     * Get the backend config.
+     * @return backend configuration
+     */
+    public BackendConfig getBackendConfig() {
+        return backendConfig;
+    }
+
+    public String getAdminHost() {
+        String adminHost = startupOptions.getStringOption(
+                AdminServerOption.ADMIN_HOST);
+        if (adminHost == null) {
+            adminHost = adminServerConfig.getAdminHost();
+        }
+        return adminHost;
+    }
+
+    /**
+     * Check admin tcp setting and see if any bad.
+     * @return valid tcp port or -1 if not allowTcp
+     * @throws KrbException e
+     */
+    public int checkGetAdminTcpPort() throws KrbException {
+        if (allowTcp()) {
+            int adminPort = getAdminTcpPort();
+            if (adminPort < 1) {
+                throw new KrbException("Admin Server tcp port isn't set or configured");
+            }
+            return adminPort;
+        }
+        return -1;
+    }
+
+    /**
+     * Check admin udp setting and see if any bad.
+     * @return valid udp port or -1 if not allowUdp
+     * @throws KrbException e
+     */
+    public int checkGetAdminUdpPort() throws KrbException {
+        if (allowUdp()) {
+            int adminPort = getAdminUdpPort();
+            if (adminPort < 1) {
+                throw new KrbException("Admin Server udp port isn't set or configured");
+            }
+            return adminPort;
+        }
+        return -1;
+    }
+
+    /**
+     * Get admin tcp port
+     *
+     * @return admin tcp port
+     */
+    public int getAdminTcpPort() {
+        int tcpPort = startupOptions.getIntegerOption(AdminServerOption.ADMIN_TCP_PORT);
+        if (tcpPort < 1) {
+            tcpPort = adminServerConfig.getAdminTcpPort();
+        }
+        if (tcpPort < 1) {
+            tcpPort = getAdminPort();
+        }
+
+        return tcpPort;
+    }
+
+    /**
+     * Get admin port
+     *
+     * @return admin port
+     */
+    public int getAdminPort() {
+        int adminPort = startupOptions.getIntegerOption(AdminServerOption.ADMIN_PORT);
+        if (adminPort < 1) {
+            adminPort = adminServerConfig.getAdminPort();
+        }
+        return adminPort;
+    }
+
+    /**
+     * Get whether tcp protocol is allowed
+     * @return tcp protocol is allowed or not
+     */
+    public boolean allowTcp() {
+        Boolean allowTcp = startupOptions.getBooleanOption(
+                AdminServerOption.ALLOW_TCP, adminServerConfig.allowTcp());
+        return allowTcp;
+    }
+
+    /**
+     * Get whether udp protocol is allowed
+     * @return udp protocol is allowed or not
+     */
+    public boolean allowUdp() {
+        Boolean allowUdp = startupOptions.getBooleanOption(
+                AdminServerOption.ALLOW_UDP, adminServerConfig.allowUdp());
+        return allowUdp;
+    }
+
+    /**
+     * Get admin udp port
+     *
+     * @return udp port
+     */
+    public int getAdminUdpPort() {
+        int udpPort = startupOptions.getIntegerOption(AdminServerOption.ADMIN_UDP_PORT);
+        if (udpPort < 1) {
+            udpPort = adminServerConfig.getAdminUdpPort();
+        }
+        if (udpPort < 1) {
+            udpPort = getAdminPort();
+        }
+
+        return udpPort;
+    }
+
+    /**
+     * Get Admin Server realm.
+     * @return Admin Server realm
+     */
+    public String getAdminRealm() {
+        String adminRealm = startupOptions.getStringOption(AdminServerOption.ADMIN_REALM);
+        if (adminRealm == null || adminRealm.isEmpty()) {
+            adminRealm = adminServerConfig.getAdminRealm();
+        }
+        return adminRealm;
+    }
+}


Mime
View raw message