Merge remote-tracking branch 'asf/trunk' into kadmin-remote
diff --git a/kerby-common/kerby-asn1/pom.xml b/kerby-common/kerby-asn1/pom.xml
index 8b1e23c..26dbef8 100644
--- a/kerby-common/kerby-asn1/pom.xml
+++ b/kerby-common/kerby-asn1/pom.xml
@@ -26,7 +26,4 @@
<name>Kerby ASN1 Project</name>
<description>Kerby ASN1 Project</description>
- <dependencies>
- </dependencies>
-
</project>
diff --git a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java
index e0166ec..5b9a65f 100644
--- a/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java
+++ b/kerby-common/kerby-asn1/src/main/java/org/apache/kerby/asn1/EnumType.java
@@ -20,7 +20,7 @@
package org.apache.kerby.asn1;
/**
- * A helper interface used by Asn1Enumerated.
+ * A helper interface for enum types.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
diff --git a/kerby-common/kerby-xdr/pom.xml b/kerby-common/kerby-xdr/pom.xml
new file mode 100644
index 0000000..d6ad54c
--- /dev/null
+++ b/kerby-common/kerby-xdr/pom.xml
@@ -0,0 +1,29 @@
+<?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/xsd/maven-4.0.0.xsd">
+
+ <parent>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-common</artifactId>
+ <version>1.0.0-RC3-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>kerby-xdr</artifactId>
+ <name>Kerby XDR Project</name>
+ <description>Kerby XDR Project</description>
+
+</project>
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/EnumType.java
similarity index 67%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/EnumType.java
index 325f1db..0936863 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/EnumType.java
@@ -6,19 +6,32 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.xdr;
-public class KadminTest {
-
+/**
+ * A helper interface for enum types.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface EnumType {
+ /**
+ * @return the Enum element value
+ */
+ int getValue();
+
+ /**
+ * @return The enum element name
+ */
+ String getName();
}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/XdrDataType.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/XdrDataType.java
new file mode 100644
index 0000000..34bc014
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/XdrDataType.java
@@ -0,0 +1,55 @@
+/**
+ * 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;
+
+/**
+ * An enumeration for every XDR type.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public enum XdrDataType {
+ UNKNOWN (-1),
+ BOOLEAN (0x01),
+ INTEGER (0x02),
+ BYTES (0x03),
+ STRING (0X04),
+ ENUM (0x05),
+ OPAQUE (0x06),
+ UNSIGNED_INTEGER (0x07),
+ STRUCT (0x08),
+ UNION (0x09);
+
+ /** The dataType value */
+ private int value;
+
+ /**
+ * Create an instance of this class
+ */
+ XdrDataType(int value) {
+ this.value = value;
+ }
+
+ /**
+ * @return The associated dataType value
+ */
+ public int getValue() {
+ return value;
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/XdrFieldInfo.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/XdrFieldInfo.java
new file mode 100644
index 0000000..2ab727c
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/XdrFieldInfo.java
@@ -0,0 +1,53 @@
+/**
+ * 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;
+
+/**
+ * Representing a field in a XDR struct.
+ */
+public class XdrFieldInfo {
+ private int index;
+ private XdrDataType dataType;
+ private Object value;
+
+ /**
+ * Constructor.
+ * @param index
+ * @param dataType
+ *
+ */
+ public XdrFieldInfo(int index, XdrDataType dataType, Object value) {
+ this.index = index;
+ this.dataType = dataType;
+ this.value = value;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public XdrDataType getDataType() {
+ return dataType;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/AbstractXdrType.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/AbstractXdrType.java
new file mode 100644
index 0000000..68facec
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/AbstractXdrType.java
@@ -0,0 +1,100 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * The abstract XDR type for all the XDR types. It provides basic
+ * encoding and decoding utilities.
+ *
+ * @param <T> the type of the value encoded/decoded or wrapped by this
+ */
+public abstract class AbstractXdrType<T> implements XdrType {
+ private XdrDataType dataType;
+
+ // The wrapped real value.
+ private T value;
+
+ /**
+ * Default constructor.
+ * @param dataType the dataType
+ * @param value the value
+ */
+ public AbstractXdrType(XdrDataType dataType, T value) {
+ this(dataType);
+ this.value = value;
+ }
+
+ /**
+ * Default constructor.
+ * @param dataType the dataType
+ */
+ public AbstractXdrType(XdrDataType dataType) {
+ this.dataType = dataType;
+ }
+
+ @Override
+ public byte[] encode() throws IOException {
+ int len = encodingLength();
+ ByteBuffer byteBuffer = ByteBuffer.allocate(len);
+ encode(byteBuffer);
+ byteBuffer.flip();
+ return byteBuffer.array();
+ }
+
+ @Override
+ public void encode(ByteBuffer buffer) throws IOException {
+ encodeBody(buffer);
+ }
+
+ protected abstract void encodeBody(ByteBuffer buffer) throws IOException;
+
+ @Override
+ public void decode(byte[] content) throws IOException {
+ decode(ByteBuffer.wrap(content));
+ }
+
+ @Override
+ public int encodingLength() throws IOException {
+ return encodingBodyLength();
+ }
+
+ protected abstract int encodingBodyLength() throws IOException;
+
+ @Override
+ public void decode(ByteBuffer content) throws IOException {
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+ public void setValue(T value) {
+ this.value = value;
+ }
+
+ public XdrDataType getDataType() {
+ return dataType;
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrBoolean.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrBoolean.java
new file mode 100644
index 0000000..e8e092f
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrBoolean.java
@@ -0,0 +1,94 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/**
+ * Xdr Boolean type from RFC 4506
+ * Boolean type has the same representation as signed integers.
+ */
+public class XdrBoolean extends XdrSimple<Boolean> {
+ private static final byte[] TRUE_BYTE = new byte[]
+ {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01};
+ private static final byte[] FALSE_BYTE = new byte[]
+ {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
+
+ public static final XdrBoolean TRUE = new XdrBoolean(true);
+ public static final XdrBoolean FALSE = new XdrBoolean(false);
+
+ /**
+ * Default constructor, generally for decoding as a container
+ */
+ public XdrBoolean() {
+ this(null);
+ }
+
+ /**
+ * Constructor with a value, generally for encoding of the value
+ * @param value The boolean value
+ */
+ public XdrBoolean(Boolean value) {
+ super(XdrDataType.BOOLEAN, value);
+ }
+
+ /**
+ * The length of a signed integer is 4.
+ * @return Length of a boolean type.
+ */
+ @Override
+ protected int encodingBodyLength() {
+ return 4;
+ }
+
+ /**
+ * Encode boolean type to bytes.
+ */
+ @Override
+ protected void toBytes() {
+ setBytes(getValue() ? TRUE_BYTE : FALSE_BYTE);
+ }
+
+ /**
+ * Decode bytes to boolean value.
+ * @throws IOException Wrong bytes for boolean.
+ */
+ @Override
+ protected void toValue() throws IOException {
+ if (getBytes().length != 4) {
+ byte[] boolBytes = ByteBuffer.allocate(4).put(getBytes(), 0, 4).array();
+ /**reset bytes in case the enum type is in a struct or union*/
+ setBytes(boolBytes);
+ }
+
+ byte[] bytes = getBytes();
+ if (Arrays.equals(bytes, TRUE_BYTE)) {
+ setValue(true);
+ } else if (Arrays.equals(bytes, FALSE_BYTE)) {
+ setValue(false);
+ } else {
+ throw new IOException("Fail to decode boolean type: " + bytes.toString());
+ }
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrBytes.java
similarity index 66%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrBytes.java
index 325f1db..105ff74 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrBytes.java
@@ -17,8 +17,29 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.xdr.type;
-public class KadminTest {
+import org.apache.kerby.xdr.XdrDataType;
+import java.io.IOException;
+
+public class XdrBytes extends XdrSimple<byte[]> {
+
+ public XdrBytes() {
+ this(null);
+ }
+
+ public XdrBytes(byte[] value) {
+ super(XdrDataType.BYTES, value);
+ }
+
+ @Override
+ protected void toValue() throws IOException {
+
+ }
+
+ @Override
+ protected void toBytes() {
+
+ }
}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrEnumerated.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrEnumerated.java
new file mode 100644
index 0000000..e04b484
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrEnumerated.java
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.xdr.type;
+
+import org.apache.kerby.xdr.EnumType;
+import org.apache.kerby.xdr.XdrDataType;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+public abstract class XdrEnumerated<T extends EnumType> extends XdrSimple<T> {
+ /**
+ * Default constructor, generally for decoding as a container
+ */
+ public XdrEnumerated() {
+ this(null);
+ }
+
+ /**
+ * Constructor with a value, generally for encoding of the value
+ * @param value The Enum value
+ */
+ public XdrEnumerated(T value) {
+ super(XdrDataType.ENUM, value);
+ }
+
+ protected void toBytes() {
+ byte[] bytes = ByteBuffer.allocate(4).putInt(getValue().getValue()).array();
+ setBytes(bytes);
+ }
+
+ protected void toValue() {
+ if (getBytes().length != 4) {
+ byte[] intBytes = ByteBuffer.allocate(4).put(getBytes(), 0, 4).array();
+ /**reset bytes in case the enum type is in a struct or union*/
+ setBytes(intBytes);
+ }
+ BigInteger biVal = new BigInteger(getBytes());
+ int iVal = biVal.intValue();
+ EnumType[] allValues = getAllEnumValues();
+ for (EnumType val : allValues) {
+ if (val.getValue() == iVal) {
+ setValue((T) val);
+ }
+ }
+ }
+
+ protected abstract EnumType[] getAllEnumValues();
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrInteger.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrInteger.java
new file mode 100644
index 0000000..478cf80
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrInteger.java
@@ -0,0 +1,85 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+import java.nio.ByteBuffer;
+
+/**
+ * Xdr Integer type from RFC 4506
+ * An XDR signed integer is a 32-bit datum
+ * that encodes an integer in the range [-2147483648,2147483647].
+ * The integer is represented in two's complement notation.
+ * The most and least significant bytes are0 and 3, respectively.
+ * Integers are declared as follows:
+ * int identifier;
+ *
+ * (MSB) (LSB)
+ * +-------+-------+-------+-------+
+ * |byte 0 |byte 1 |byte 2 |byte 3 |
+ * +-------+-------+-------+-------+
+ * <------------32 bits------------>
+ */
+public class XdrInteger extends XdrSimple<Integer> {
+ public XdrInteger() {
+ this((Integer) null);
+ }
+
+ public XdrInteger(Integer value) {
+ super(XdrDataType.INTEGER, value);
+ }
+
+ /**
+ * The length of a signed integer is 4.
+ * @return Length of a signed integer type.
+ */
+ @Override
+ protected int encodingBodyLength() {
+ return 4; /**Length of XdrInteger is fixed as 4 bytes*/
+ }
+
+ /**
+ * Encode Integer type to bytes.
+ * Cannot only use toByteArray() because of fixed 4 bytes length.
+ */
+ @Override
+ protected void toBytes() {
+ int value = getValue().intValue();
+ ByteBuffer buffer = ByteBuffer.allocate(4);
+ buffer.putInt(value);
+ buffer.flip();
+ setBytes(buffer.array());
+ }
+
+ /**
+ * Decode bytes to Integer value.
+ */
+ @Override
+ protected void toValue() {
+ if (getBytes().length != 4) {
+ byte[] intBytes = ByteBuffer.allocate(4).put(getBytes(), 0, 4).array();
+ /**reset bytes in case the enum type is in a struct or union*/
+ setBytes(intBytes);
+ }
+ ByteBuffer buffer = ByteBuffer.wrap(getBytes());
+ setValue(buffer.getInt());
+ }
+
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrSimple.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrSimple.java
new file mode 100644
index 0000000..a3e13b1
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrSimple.java
@@ -0,0 +1,132 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Xdr simple type, of single value other than complex type of multiple values.
+ * Including: Bytes, Integer, Boolean, String.
+ * Use toBytes() for encoding, toValue() for decoding.
+ */
+public abstract class XdrSimple<T> extends AbstractXdrType<T> {
+ private byte[] bytes;
+
+ /**
+ * Default constructor, generally for decoding as a value container
+ * @param dataTypeNo The dataType number
+ */
+ public XdrSimple(XdrDataType dataTypeNo) {
+ this(dataTypeNo, null);
+ }
+
+ /**
+ * Constructor with a value, generally for encoding of the value
+ * @param xdrDataType The dataType number
+ * @param value The value
+ */
+ public XdrSimple(XdrDataType xdrDataType, T value) {
+ super(xdrDataType, value);
+ }
+
+ protected byte[] getBytes() {
+ return bytes;
+ }
+
+ protected void setBytes(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ protected byte[] encodeBody() throws IOException {
+ if (bytes == null) {
+ /**Terminal step for encoding all the simple type to bytes.*/
+ toBytes();
+ }
+ return bytes;
+ }
+
+ /**
+ * Put encoded bytes into buffer.
+ * @param buffer ByteBuffer to hold encoded bytes.
+ */
+ @Override
+ protected void encodeBody(ByteBuffer buffer) throws IOException {
+ byte[] body = encodeBody();
+ if (body != null) {
+ buffer.put(body);
+ }
+ }
+
+ /**
+ * Length including null bytes to maintain an multiple of 4.
+ * @return
+ */
+ @Override
+ protected int encodingBodyLength() throws IOException {
+ if (getValue() == null) {
+ return 0;
+ }
+ if (bytes == null) {
+ /**Terminal step for decoding all the simple type to bytes.*/
+ toBytes();
+ }
+ return bytes.length;
+ }
+
+ @Override
+ public void decode(ByteBuffer content) throws IOException {
+ decodeBody(content);
+ }
+
+ protected void decodeBody(ByteBuffer body) throws IOException {
+ byte[] result = body.array();
+ if (result.length > 0) {
+ setBytes(result);
+ /**Terminal step for decoding all the bytes into simple types.*/
+ toValue();
+ }
+ }
+
+ /**
+ * Decode bytes to simple value.
+ */
+ protected abstract void toValue() throws IOException;
+
+ /**
+ * Encode simple type to bytes.
+ */
+ protected abstract void toBytes() throws IOException;
+
+ public static boolean isSimple(XdrDataType dataType) {
+ switch (dataType) {
+ case BOOLEAN:
+ case INTEGER:
+ case UNSIGNED_INTEGER:
+ case ENUM:
+ case STRING:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrString.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrString.java
new file mode 100644
index 0000000..32b2302
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrString.java
@@ -0,0 +1,346 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.xdr.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * From RFC 4506 :
+ *
+ * 0 1 2 3 4 5 ...
+ * +-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
+ * | length n |byte0|byte1|...| n-1 | 0 |...| 0 |
+ * +-----+-----+-----+-----+-----+-----+...+-----+-----+...+-----+
+ * |<-------4 bytes------->|<------n bytes------>|<---r bytes--->|
+ * |<----n+r (where (n+r) mod 4 = 0)---->|
+ * STRING
+ */
+public class XdrString extends XdrSimple<String> {
+ private int padding;
+
+ public XdrString() {
+ this((String) null);
+ }
+
+ public XdrString(String value) {
+ super(XdrDataType.STRING, value);
+ }
+
+ @Override
+ protected void toBytes() {
+ if (getValue() != null) {
+ /**Default value of byte is 0. So we don't have to initialize it with 0*/
+ byte[] bytes = new byte[encodingBodyLength()];
+ int length = bytes.length - padding - 4;
+ bytes[0] = (byte) (length >> 24);
+ bytes[1] = (byte) (length >> 16);
+ bytes[2] = (byte) (length >> 8);
+ bytes[3] = (byte) (length);
+ System.arraycopy(getValue().getBytes(), 0, bytes, 4, length);
+ setBytes(bytes);
+ }
+ }
+
+ @Override
+ protected int encodingBodyLength() {
+ if (getValue() != null) {
+ padding = (4 - getValue().length() % 4) % 4;
+ return getValue().length() + padding + 4;
+ }
+ return 0;
+ }
+
+ protected void toValue() throws IOException {
+ byte[] bytes = getBytes();
+ byte[] header = new byte[4];
+ System.arraycopy(bytes, 0, header, 0, 4);
+ int stringLen = ByteBuffer.wrap(header).getInt();
+ int paddingBytes = (4 - (stringLen % 4)) % 4;
+ validatePaddingBytes(paddingBytes);
+ setPadding(paddingBytes);
+
+ if (bytes.length != stringLen + 4 + paddingBytes) {
+ int totalLength = stringLen + paddingBytes + 4;
+ byte[] stringBytes = ByteBuffer.allocate(totalLength).put(getBytes(),
+ 0, totalLength).array();
+ /**reset bytes in case the enum type is in a struct or union*/
+ setBytes(stringBytes);
+ }
+
+ byte[] content = new byte[stringLen];
+ if (bytes.length > 1) {
+ System.arraycopy(bytes, 4, content, 0, stringLen);
+ }
+ setValue(new String(content, StandardCharsets.US_ASCII));
+ }
+
+ public void setPadding(int padding) {
+ this.padding = padding;
+ }
+
+ public int getPadding() {
+ return padding;
+ }
+
+ public static String fromUTF8ByteArray(byte[] bytes) {
+ int i = 0;
+ int length = 0;
+
+ while (i < bytes.length) {
+ length++;
+ if ((bytes[i] & 0xf0) == 0xf0) {
+ // surrogate pair
+ length++;
+ i += 4;
+ } else if ((bytes[i] & 0xe0) == 0xe0) {
+ i += 3;
+ } else if ((bytes[i] & 0xc0) == 0xc0) {
+ i += 2;
+ } else {
+ i += 1;
+ }
+ }
+
+ char[] cs = new char[length];
+ i = 0;
+ length = 0;
+
+ while (i < bytes.length) {
+ char ch;
+
+ if ((bytes[i] & 0xf0) == 0xf0) {
+ int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i + 1] & 0x3F) << 12)
+ | ((bytes[i + 2] & 0x3F) << 6) | (bytes[i + 3] & 0x3F);
+ int u = codePoint - 0x10000;
+ char w1 = (char) (0xD800 | (u >> 10));
+ char w2 = (char) (0xDC00 | (u & 0x3FF));
+ cs[length++] = w1;
+ ch = w2;
+ i += 4;
+ } else if ((bytes[i] & 0xe0) == 0xe0) {
+ ch = (char) (((bytes[i] & 0x0f) << 12)
+ | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
+ i += 3;
+ } else if ((bytes[i] & 0xd0) == 0xd0) {
+ ch = (char) (((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ } else if ((bytes[i] & 0xc0) == 0xc0) {
+ ch = (char) (((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ } else {
+ ch = (char) (bytes[i] & 0xff);
+ i += 1;
+ }
+
+ cs[length++] = ch;
+ }
+
+ return new String(cs);
+ }
+
+ public static byte[] toUTF8ByteArray(String string) {
+ return toUTF8ByteArray(string.toCharArray());
+ }
+
+ public static byte[] toUTF8ByteArray(char[] string) {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try {
+ toUTF8ByteArray(string, bOut);
+ } catch (IOException e) {
+ throw new IllegalStateException("cannot encode string to byte array!");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ public static void toUTF8ByteArray(char[] string, OutputStream sOut) throws IOException {
+ char[] c = string;
+ int i = 0;
+
+ while (i < c.length) {
+ char ch = c[i];
+
+ if (ch < 0x0080) {
+ sOut.write(ch);
+ } else if (ch < 0x0800) {
+ sOut.write(0xc0 | (ch >> 6));
+ sOut.write(0x80 | (ch & 0x3f));
+ } else if (ch >= 0xD800 && ch <= 0xDFFF) {
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (i + 1 >= c.length) {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ char w1 = ch;
+ ch = c[++i];
+ char w2 = ch;
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (w1 > 0xDBFF) {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ int codePoint = ((w1 & 0x03FF) << 10) | (w2 & 0x03FF) + 0x10000;
+ sOut.write(0xf0 | (codePoint >> 18));
+ sOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+ sOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+ sOut.write(0x80 | (codePoint & 0x3F));
+ } else {
+ sOut.write(0xe0 | (ch >> 12));
+ sOut.write(0x80 | ((ch >> 6) & 0x3F));
+ sOut.write(0x80 | (ch & 0x3F));
+ }
+
+ i++;
+ }
+ }
+
+ /**
+ * A locale independent version of toUpperCase.
+ *
+ * @param string input to be converted
+ * @return a US Ascii uppercase version
+ */
+ public static String toUpperCase(String string) {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++) {
+ char ch = chars[i];
+ if ('a' <= ch && 'z' >= ch) {
+ changed = true;
+ chars[i] = (char) (ch - 'a' + 'A');
+ }
+ }
+
+ if (changed) {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ /**
+ * A locale independent version of toLowerCase.
+ *
+ * @param string input to be converted
+ * @return a US ASCII lowercase version
+ */
+ public static String toLowerCase(String string) {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++) {
+ char ch = chars[i];
+ if ('A' <= ch && 'Z' >= ch) {
+ changed = true;
+ chars[i] = (char) (ch - 'A' + 'a');
+ }
+ }
+
+ if (changed) {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ public static byte[] toByteArray(char[] chars) {
+ byte[] bytes = new byte[chars.length];
+
+ for (int i = 0; i != bytes.length; i++) {
+ bytes[i] = (byte) chars[i];
+ }
+
+ return bytes;
+ }
+
+ public static byte[] toByteArray(String string) {
+ byte[] bytes = new byte[string.length()];
+
+ for (int i = 0; i != bytes.length; i++) {
+ char ch = string.charAt(i);
+
+ bytes[i] = (byte) ch;
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Convert an array of 8 bit characters into a string.
+ *
+ * @param bytes 8 bit characters.
+ * @return resulting String.
+ */
+ public static String fromByteArray(byte[] bytes) {
+ return new String(asCharArray(bytes));
+ }
+
+ /**
+ * Do a simple conversion of an array of 8 bit characters into a string.
+ *
+ * @param bytes 8 bit characters.
+ * @return resulting String.
+ */
+ public static char[] asCharArray(byte[] bytes) {
+ char[] chars = new char[bytes.length];
+
+ for (int i = 0; i != chars.length; i++) {
+ chars[i] = (char) (bytes[i] & 0xff);
+ }
+
+ return chars;
+ }
+
+ public static String[] split(String input, char delimiter) {
+ List<String> v = new ArrayList<String>();
+ boolean moreTokens = true;
+ String subString;
+
+ while (moreTokens) {
+ int tokenLocation = input.indexOf(delimiter);
+ if (tokenLocation > 0) {
+ subString = input.substring(0, tokenLocation);
+ v.add(subString);
+ input = input.substring(tokenLocation + 1);
+ } else {
+ moreTokens = false;
+ v.add(input);
+ }
+ }
+
+ return v.toArray(new String[v.size()]);
+ }
+
+ private void validatePaddingBytes(int paddingBytes) throws IOException {
+ if (paddingBytes < 0 || paddingBytes > 3) {
+ throw new IOException("Bad padding number: " + paddingBytes + ", should be in [0, 3]");
+ }
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrStructType.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrStructType.java
new file mode 100644
index 0000000..6bb74a5
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrStructType.java
@@ -0,0 +1,99 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * For collection type that may consist of dataTypeged fields
+ */
+public abstract class XdrStructType extends AbstractXdrType<XdrStructType> {
+ private XdrFieldInfo[] fieldInfos;
+ private XdrType[] fields;
+
+ public XdrStructType(XdrDataType xdrDataType) {
+ super(xdrDataType);
+ this.fieldInfos = null;
+ this.fields = null;
+ }
+
+ public XdrStructType(XdrDataType xdrDataType,
+ final XdrFieldInfo[] fieldInfos) {
+ super(xdrDataType);
+ this.fieldInfos = fieldInfos;
+ this.fields = new XdrType[fieldInfos.length];
+
+ getStructTypeInstance(this.fields, fieldInfos);
+ }
+
+ protected abstract void getStructTypeInstance(final XdrType[] fields, final XdrFieldInfo[] fieldInfos);
+
+ public XdrFieldInfo[] getXdrFieldInfos() {
+ return fieldInfos;
+ }
+
+ @Override
+ protected int encodingBodyLength() throws IOException {
+ int allLen = 0;
+ for (int i = 0; i < fields.length; ++i) {
+ AbstractXdrType field = (AbstractXdrType) fields[i];
+ if (field != null) {
+ allLen += field.encodingLength();
+ }
+ }
+ return allLen;
+ }
+
+ @Override
+ protected void encodeBody(ByteBuffer buffer) throws IOException {
+ for (int i = 0; i < fields.length; ++i) {
+ XdrType field = fields[i];
+ if (field != null) {
+ field.encode(buffer);
+ }
+ }
+ }
+
+ @Override
+ public void decode(ByteBuffer content) throws IOException {
+ AbstractXdrType[] fields = getAllFields();
+ Object[] value;
+ for (int i = 0; i < fields.length; i++) {
+ if (fields[i] != null) {
+ fields[i].decode(content);
+ int length = fields[i].encodingLength();
+ byte[] array = content.array();
+ byte[] newArray = new byte[array.length - length];
+ System.arraycopy(array, length, newArray, 0, array.length - length);
+ content = ByteBuffer.wrap(newArray);
+ }
+ }
+ this.fields = fields;
+ setValue(fieldsToValues(fields));
+ }
+
+ protected abstract XdrStructType fieldsToValues(AbstractXdrType[] fields);
+
+ protected abstract AbstractXdrType[] getAllFields();
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrType.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrType.java
new file mode 100644
index 0000000..6840e59
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrType.java
@@ -0,0 +1,62 @@
+/**
+ * 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.type;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * The ASN1 type interface for all ASN1 types.
+ */
+public interface XdrType {
+
+ /**
+ * Get length of encoding bytes by just calculating without real encoding.
+ * Generally it's called to prepare for the encoding buffer.
+ * @return length of encoding bytes
+ */
+ int encodingLength() throws IOException;
+
+ /**
+ * Encode the type, by recursively.
+ * @return encoded bytes
+ */
+ byte[] encode() throws IOException;
+
+ /**
+ * Encode the type, by recursively, using the provided buffer.
+ * @param buffer The byte buffer
+ */
+ void encode(ByteBuffer buffer) throws IOException;
+
+ /**
+ * Decode the content bytes into this type.
+ * @param content The content bytes
+ * @throws IOException e
+ */
+ void decode(byte[] content) throws IOException;
+
+ /**
+ * Decode the content bytes into this type.
+ * @param content The content bytes
+ * @throws IOException e
+ */
+ void decode(ByteBuffer content) throws IOException;
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrUnion.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrUnion.java
new file mode 100644
index 0000000..b7dc59c
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrUnion.java
@@ -0,0 +1,131 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * A discriminated union is a type composed of a discriminant followed
+ * by a type selected from a set of prearranged types according to the
+ * value of the discriminant. The type of discriminant is either "int",
+ * "unsigned int", or an enumerated type, such as "bool". The component
+ * types are called "arms" of the union and are preceded by the value of
+ * the discriminant that implies their encoding. Discriminated unions
+ * are declared as follows:
+ *
+ * union switch (discriminant-declaration) {
+ * case discriminant-value-A:
+ * arm-declaration-A;
+ * case discriminant-value-B:
+ * arm-declaration-B;
+ * ...
+ * default: default-declaration;
+ * } identifier;
+ * Each "case" keyword is followed by a legal value of the discriminant.
+ * The default arm is optional. If it is not specified, then a valid
+ * encoding of the union cannot take on unspecified discriminant values.
+ * The size of the implied arm is always a multiple of four bytes.
+ *
+ * The discriminated union is encoded as its discriminant followed by
+ * the encoding of the implied arm.
+ * 0 1 2 3
+ * +---+---+---+---+---+---+---+---+
+ * | discriminant | implied arm |
+ * +---+---+---+---+---+---+---+---+
+ * |<---4 bytes--->|
+ */
+public abstract class XdrUnion extends AbstractXdrType<XdrUnion> {
+ /**
+ * [0] is the discriminant
+ * index, XdrDataType, value;
+ * [1] is the implied arm
+ */
+ private XdrFieldInfo[] fieldInfos;
+ private XdrType[] fields;
+
+ public XdrUnion(XdrDataType xdrDataType) {
+ super(xdrDataType);
+ this.fieldInfos = null;
+ this.fields = null;
+ }
+
+ public XdrUnion(XdrDataType xdrDataType,
+ final XdrFieldInfo[] fieldInfos) {
+ super(xdrDataType);
+ this.fieldInfos = fieldInfos;
+ this.fields = new XdrType[fieldInfos.length];
+
+ getUnionInstance(this.fields, fieldInfos);
+ }
+
+ protected abstract void getUnionInstance(final XdrType[] fields, final XdrFieldInfo[] fieldInfos);
+
+ public XdrFieldInfo[] getXdrFieldInfos() {
+ return fieldInfos;
+ }
+
+ @Override
+ protected int encodingBodyLength() throws IOException {
+ int allLen = 0;
+ for (int i = 0; i < fields.length; i++) {
+ AbstractXdrType field = (AbstractXdrType) fields[i];
+ if (field != null) {
+ allLen += field.encodingLength();
+ }
+ }
+ return allLen;
+ }
+
+ @Override
+ protected void encodeBody(ByteBuffer buffer) throws IOException {
+ for (int i = 0; i < fields.length; ++i) {
+ XdrType field = fields[i];
+ if (field != null) {
+ field.encode(buffer);
+ }
+ }
+ }
+
+ @Override
+ public void decode(ByteBuffer content) throws IOException {
+ AbstractXdrType[] fields = getAllFields();
+ Object[] value;
+ for (int i = 0; i < fields.length; i++) {
+ if (fields[i] != null) {
+ fields[i].decode(content);
+ int length = fields[i].encodingLength();
+ byte[] array = content.array();
+ byte[] newArray = new byte[array.length - length];
+ System.arraycopy(array, length, newArray, 0, array.length - length);
+ content = ByteBuffer.wrap(newArray);
+ }
+ }
+ this.fields = fields;
+ setValue(fieldsToValues(fields));
+ }
+
+ protected abstract XdrUnion fieldsToValues(AbstractXdrType[] fields);
+
+ protected abstract AbstractXdrType[] getAllFields();
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrUnsignedInteger.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrUnsignedInteger.java
new file mode 100644
index 0000000..ad1df69
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrUnsignedInteger.java
@@ -0,0 +1,100 @@
+/**
+ * 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.type;
+
+import org.apache.kerby.xdr.XdrDataType;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Xdr Unsigned Integer type from RFC 4506
+ * An XDR unsigned integer is a 32-bit datum that encodes
+ * a non-negative integer in the range [0,4294967295].
+ * It is represented by an unsigned binary number whose most
+ * and least significant bytes are 0 and 3, respectively.
+ * An unsigned integer is declared as follows:
+ * unsigned int identifier;
+ *
+ * (MSB) (LSB)
+ * +-------+-------+-------+-------+
+ * |byte 0 |byte 1 |byte 2 |byte 3 |
+ * +-------+-------+-------+-------+
+ * <------------32 bits------------>
+ */
+public class XdrUnsignedInteger extends XdrSimple<Long> {
+ public XdrUnsignedInteger() {
+ this((Long) null);
+ }
+
+ public XdrUnsignedInteger(String value) {
+ this(Long.valueOf(value));
+ }
+
+ public XdrUnsignedInteger(Long value) {
+ super(XdrDataType.UNSIGNED_INTEGER, value);
+ }
+
+ /**
+ * The length of an unsigned integer is 4.
+ * @return Length of a unsigned integer type.
+ */
+ @Override
+ protected int encodingBodyLength() {
+ return 4; /**Length of XdrInteger is fixed as 4 bytes*/
+ }
+
+ /**
+ * Encode Unsigned Integer type to bytes.
+ */
+ @Override
+ protected void toBytes() throws IOException {
+ Long value = getValue();
+ validateUnsignedInteger(value); /**Check whether the long value is valid unsigned int*/
+ ByteBuffer buffer = ByteBuffer.allocate(8);
+ buffer.putLong(value);
+ byte[] bytes = new byte[4]; /**The encoding length is 4*/
+ System.arraycopy(buffer.array(), 4, bytes, 0, 4);
+ setBytes(bytes);
+ }
+
+ private void validateUnsignedInteger(Long value) throws IOException {
+ if (value < 0 || value > 4294967295L) {
+ throw new IOException("Invalid unsigned integer: " + value);
+ }
+ }
+
+ /**
+ * Decode bytes to Unsigned Integer value.
+ */
+ @Override
+ protected void toValue() {
+ if (getBytes().length != 4) {
+ byte[] bytes = ByteBuffer.allocate(4).put(getBytes(), 0, 4).array();
+ setBytes(bytes); /**reset bytes in case the enum type is in a struct or union*/
+ }
+
+ byte[] longBytes = {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
+ System.arraycopy(getBytes(), 0, longBytes, 4, 4);
+ ByteBuffer buffer = ByteBuffer.wrap(longBytes);
+ setValue(buffer.getLong());
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/HexUtil.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/HexUtil.java
new file mode 100644
index 0000000..70a2b1c
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/HexUtil.java
@@ -0,0 +1,113 @@
+/**
+ * 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.util;
+
+/**
+ * This is only for test, be careful when use in production codes.
+ */
+public class HexUtil {
+
+ static final String HEX_CHARS_STR = "0123456789ABCDEF";
+ static final char[] HEX_CHARS = HEX_CHARS_STR.toCharArray();
+
+ /**
+ * Convert bytes into friendly format as:
+ * 0x02 02 00 80
+ */
+ public static String bytesToHexFriendly(byte[] bytes) {
+ int len = bytes.length * 2;
+ len += bytes.length; // for ' ' appended for each char
+ len += 2; // for '0x' prefix
+ char[] hexChars = new char[len];
+ hexChars[0] = '0';
+ hexChars[1] = 'x';
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 3 + 2] = HEX_CHARS[v >>> 4];
+ hexChars[j * 3 + 3] = HEX_CHARS[v & 0x0F];
+ hexChars[j * 3 + 4] = ' ';
+ }
+
+ return new String(hexChars);
+ }
+
+ /**
+ * Convert friendly hex string like follows into byte array
+ * 0x02 02 00 80
+ */
+ public static byte[] hex2bytesFriendly(String hexString) {
+ hexString = hexString.toUpperCase();
+ String hexStr = hexString;
+ if (hexString.startsWith("0X")) {
+ hexStr = hexString.substring(2);
+ }
+ String[] hexParts = hexStr.split(" ");
+
+ byte[] bytes = new byte[hexParts.length];
+ char[] hexPart;
+ for (int i = 0; i < hexParts.length; ++i) {
+ hexPart = hexParts[i].toCharArray();
+ if (hexPart.length != 2) {
+ throw new IllegalArgumentException("Invalid hex string to convert");
+ }
+ bytes[i] = (byte) ((HEX_CHARS_STR.indexOf(hexPart[0]) << 4)
+ + HEX_CHARS_STR.indexOf(hexPart[1]));
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Convert bytes into format as:
+ * 02020080
+ * @param bytes The bytes
+ * @return The hex string
+ */
+ public static String bytesToHex(byte[] bytes) {
+ int len = bytes.length * 2;
+ char[] hexChars = new char[len];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = HEX_CHARS[v >>> 4];
+ hexChars[j * 2 + 1] = HEX_CHARS[v & 0x0F];
+ }
+
+ return new String(hexChars);
+ }
+
+ /**
+ * Convert hex string like follows into byte array
+ * 02020080
+ * @param hexString The hex string
+ * @return The bytes
+ */
+ public static byte[] hex2bytes(String hexString) {
+ hexString = hexString.toUpperCase();
+ int len = hexString.length() / 2;
+ byte[] bytes = new byte[len];
+ char[] hexChars = hexString.toCharArray();
+ for (int i = 0, j = 0; i < len; ++i) {
+ bytes[i] = (byte) ((HEX_CHARS_STR.indexOf(hexChars[j++]) << 4)
+ + HEX_CHARS_STR.indexOf(hexChars[j++]));
+ }
+
+ return bytes;
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/IOUtil.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/IOUtil.java
new file mode 100644
index 0000000..2136511
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/IOUtil.java
@@ -0,0 +1,109 @@
+/**
+ * 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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+
+/**
+ * Some IO and file related utilities.
+ */
+public final class IOUtil {
+ private IOUtil() { }
+
+ public static byte[] readInputStream(InputStream in) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length = 0;
+ while ((length = in.read(buffer)) != -1) {
+ baos.write(buffer, 0, length);
+ }
+ in.close();
+ return baos.toByteArray();
+ }
+
+ public static void readInputStream(InputStream in,
+ byte[] buf) throws IOException {
+ int toRead = buf.length;
+ int off = 0;
+ while (toRead > 0) {
+ int ret = in.read(buf, off, toRead);
+ if (ret < 0) {
+ throw new IOException("Bad inputStream, premature EOF");
+ }
+ toRead -= ret;
+ off += ret;
+ }
+ in.close();
+ }
+
+ /**
+ * Read an input stream and return the content as string assuming UTF8.
+ * @param in The input stream
+ * @return The content
+ * @throws IOException e
+ */
+ public static String readInput(InputStream in) throws IOException {
+ byte[] content = readInputStream(in);
+ return Utf8.toString(content);
+ }
+
+ /**
+ * Read a file and return the content as string assuming UTF8.
+ * @param file The file to read
+ * @return The content
+ * @throws IOException e
+ */
+ public static String readFile(File file) throws IOException {
+ long len = 0;
+ if (file.length() >= Integer.MAX_VALUE) {
+ throw new IOException("Too large file, unexpected!");
+ } else {
+ len = file.length();
+ }
+ byte[] buf = new byte[(int) len];
+
+ InputStream is = new FileInputStream(file);
+ readInputStream(is, buf);
+
+ return Utf8.toString(buf);
+ }
+
+ /**
+ * Write a file with the content assuming UTF8.
+ * @param content The content
+ * @param file The file to write
+ * @throws IOException e
+ */
+ public static void writeFile(String content, File file) throws IOException {
+ FileOutputStream outputStream = new FileOutputStream(file);
+ FileChannel fc = outputStream.getChannel();
+
+ ByteBuffer buffer = ByteBuffer.wrap(Utf8.toBytes(content));
+ fc.write(buffer);
+ outputStream.close();
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/Utf8.java
similarity index 67%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/Utf8.java
index 325f1db..374c16f 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/Utf8.java
@@ -6,19 +6,29 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.xdr.util;
-public class KadminTest {
+import java.nio.charset.StandardCharsets;
+public final class Utf8 {
+ private Utf8() { }
+
+ public static String toString(byte[] bytes) {
+ return new String(bytes, StandardCharsets.UTF_8);
+ }
+
+ public static byte[] toBytes(String s) {
+ return s.getBytes(StandardCharsets.UTF_8);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/XdrUtil.java
similarity index 88%
rename from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
rename to kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/XdrUtil.java
index 325f1db..880bbb0 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/util/XdrUtil.java
@@ -17,8 +17,10 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.xdr.util;
-public class KadminTest {
-
+public final class XdrUtil {
+ private XdrUtil() {
+
+ }
}
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/TestUtil.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/TestUtil.java
new file mode 100644
index 0000000..6a3d9e8
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/TestUtil.java
@@ -0,0 +1,47 @@
+/**
+ * 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.util.HexUtil;
+import org.apache.kerby.xdr.util.IOUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public final class TestUtil {
+ private TestUtil() {
+
+ }
+
+ static byte[] readBytesFromTxtFile(String resource) throws IOException {
+ String hexStr = readStringFromTxtFile(resource);
+ return HexUtil.hex2bytes(hexStr);
+ }
+
+ static String readStringFromTxtFile(String resource) throws IOException {
+ InputStream is = TestUtil.class.getResourceAsStream(resource);
+ return IOUtil.readInput(is);
+ }
+
+ static byte[] readBytesFromBinFile(String resource) throws IOException {
+ InputStream is = TestUtil.class.getResourceAsStream(resource);
+ return IOUtil.readInputStream(is);
+ }
+}
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrBooleanTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrBooleanTest.java
new file mode 100644
index 0000000..0d7b0f2
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrBooleanTest.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.xdr;
+
+import org.apache.kerby.xdr.type.XdrBoolean;
+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 XdrBooleanTest {
+ @Test
+ public void testEncoding() throws IOException {
+ testEncodingWith(true, "0x00 00 00 01");
+ testEncodingWith(false, "0x00 00 00 00");
+ //what about undefined codeBytes?
+ }
+
+ private void testEncodingWith(Boolean value, String expectedEncoding) throws IOException {
+ byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+ XdrBoolean aValue = new XdrBoolean(value);
+
+ byte[] encodingBytes = aValue.encode();
+ assertThat(encodingBytes).isEqualTo(expected);
+ }
+
+ @Test
+ public void testDecoding() throws IOException {
+ testDecodingWith(true, "0x00 00 00 01");
+ testDecodingWith(false, "0x00 00 00 00");
+ //what about undefined codeBytes?
+ }
+
+ private void testDecodingWith(Boolean expectedValue, String content) throws IOException {
+ XdrBoolean decoded = new XdrBoolean();
+
+ decoded.decode(HexUtil.hex2bytesFriendly(content));
+ assertThat(decoded.getValue()).isEqualTo(expectedValue);
+ }
+
+}
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrEnumeratedInstance.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrEnumeratedInstance.java
new file mode 100644
index 0000000..e35d03c
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrEnumeratedInstance.java
@@ -0,0 +1,56 @@
+/**
+ * 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.XdrEnumerated;
+
+enum Color implements EnumType {
+ RED(2),
+ YELLOW(3),
+ BLUE(5);
+ int value;
+ Color(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getName() {
+ return name();
+ }
+}
+
+public class XdrEnumeratedInstance extends XdrEnumerated<Color> {
+
+ public XdrEnumeratedInstance() {
+ super(null);
+ }
+
+ public XdrEnumeratedInstance(Color value) {
+ super(value);
+ }
+ @Override
+ protected EnumType[] getAllEnumValues() {
+ return Color.values();
+ }
+
+}
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrEnumeratedTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrEnumeratedTest.java
new file mode 100644
index 0000000..2a3096a
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrEnumeratedTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.XdrEnumerated;
+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 XdrEnumeratedTest {
+ @Test
+ public void testEncoding() throws IOException {
+ testEncodingWith(Color.RED, "0x00 00 00 02");
+ testEncodingWith(Color.YELLOW, "0x00 00 00 03");
+ testEncodingWith(Color.BLUE, "0x00 00 00 05");
+ }
+
+ private void testEncodingWith(Color value, String expectedEncoding) throws IOException {
+ byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+ XdrEnumerated aValue = new XdrEnumeratedInstance(value);
+
+ byte[] encodingBytes = aValue.encode();
+ assertThat(encodingBytes).isEqualTo(expected);
+ }
+
+
+ @Test
+ public void testDecoding() throws IOException {
+ testDecodingWith(Color.RED, "0x00 00 00 02");
+ testDecodingWith(Color.YELLOW, "0x00 00 00 03");
+ testDecodingWith(Color.BLUE, "0x00 00 00 05");
+ }
+
+ private void testDecodingWith(Color expectedValue, String content) throws IOException {
+ XdrEnumerated decoded = new XdrEnumeratedInstance();
+ decoded.decode(HexUtil.hex2bytesFriendly(content));
+ assertThat(decoded.getValue()).isEqualTo(expectedValue);
+ }
+}
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);
+ }
+}
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);
+ }
+}
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;
+ }
+}
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());
+ }
+
+}
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;
+ }
+}
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());
+ }
+}
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);
+ }
+}
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>
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%
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
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
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
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
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
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>
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 @@
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;
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>
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!");
+ }
+}
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();
+ }
+ }
+}
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);
+ }
+}
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;
+ }
+}
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();
+ }
+}
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();
+ }
+}
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;
+ }
+}
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;
+ }
+}
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerUtil.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerUtil.java
new file mode 100644
index 0000000..f48bf5b
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/AdminServerUtil.java
@@ -0,0 +1,165 @@
+/**
+ * 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.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.identity.backend.MemoryIdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+/**
+ * Admin Server utilities.
+ */
+public final class AdminServerUtil {
+
+ private AdminServerUtil() { }
+
+ /**
+ * Get adminServer configuration
+ * @param confDir configuration directory
+ * @return adminServer configuration
+ * @throws KrbException e.
+ */
+ public static AdminServerConfig getAdminServerConfig(File confDir) throws KrbException {
+ File adminServerConfFile = new File(confDir, "adminServer.conf");
+ if (adminServerConfFile.exists()) {
+ AdminServerConfig adminServerConfig = new AdminServerConfig();
+ try {
+ adminServerConfig.addKrb5Config(adminServerConfFile);
+ } catch (IOException e) {
+ throw new KrbException("Can not load the adminServer configuration file "
+ + adminServerConfFile.getAbsolutePath());
+ }
+ return adminServerConfig;
+ }
+
+ return null;
+ }
+
+ /**
+ * Get kdc configuration
+ * @param confDir configuration directory
+ * @return kdc configuration
+ * @throws KrbException e.
+ */
+ public static KdcConfig getKdcConfig(File confDir) throws KrbException {
+ File kdcConfFile = new File(confDir, "kdc.conf");
+ if (kdcConfFile.exists()) {
+ KdcConfig kdcConfig = new KdcConfig();
+ try {
+ kdcConfig.addKrb5Config(kdcConfFile);
+ } catch (IOException e) {
+ throw new KrbException("Can not load the kdc configuration file "
+ + kdcConfFile.getAbsolutePath());
+ }
+ return kdcConfig;
+ }
+
+ return null;
+ }
+
+ /**
+ * Get backend configuration
+ * @param confDir configuration directory
+ * @return backend configuration
+ * @throws KrbException e.
+ */
+ public static BackendConfig getBackendConfig(File confDir) throws KrbException {
+ File backendConfigFile = new File(confDir, "backend.conf");
+ if (backendConfigFile.exists()) {
+ BackendConfig backendConfig = new BackendConfig();
+ try {
+ backendConfig.addIniConfig(backendConfigFile);
+ } catch (IOException e) {
+ throw new KrbException("Can not load the backend configuration file "
+ + backendConfigFile.getAbsolutePath());
+ }
+ return backendConfig;
+ }
+
+ return null;
+ }
+
+ /**
+ * Init the identity backend from backend configuration.
+ *
+ * @throws KrbException e.
+ * @param backendConfig backend configuration information
+ * @return backend
+ */
+ public static IdentityBackend getBackend(
+ BackendConfig backendConfig) throws KrbException {
+ String backendClassName = backendConfig.getString(
+ AdminServerConfigKey.KDC_IDENTITY_BACKEND, true);
+ if (backendClassName == null) {
+ backendClassName = MemoryIdentityBackend.class.getCanonicalName();
+ }
+
+ Class<?> backendClass;
+ try {
+ backendClass = Class.forName(backendClassName);
+ } catch (ClassNotFoundException e) {
+ throw new KrbException("Failed to load backend class: "
+ + backendClassName);
+ }
+
+ IdentityBackend backend;
+ try {
+ backend = (IdentityBackend) backendClass.newInstance();
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new KrbException("Failed to create backend: "
+ + backendClassName);
+ }
+
+ backend.setConfig(backendConfig);
+ backend.initialize();
+ return backend;
+ }
+
+ /**
+ * Get KDC network transport addresses according to KDC setting.
+ * @param setting kdc setting
+ * @return UDP and TCP addresses pair
+ * @throws KrbException e
+ */
+ public static TransportPair getTransportPair(
+ AdminServerSetting setting) throws KrbException {
+ TransportPair result = new TransportPair();
+
+ int tcpPort = setting.checkGetAdminTcpPort();
+ if (tcpPort > 0) {
+ result.tcpAddress = new InetSocketAddress(
+ setting.getAdminHost(), tcpPort);
+ }
+ int udpPort = setting.checkGetAdminUdpPort();
+ if (udpPort > 0) {
+ result.udpAddress = new InetSocketAddress(
+ setting.getAdminHost(), udpPort);
+ }
+
+ return result;
+ }
+}
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/AbstractInternalAdminServer.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/AbstractInternalAdminServer.java
new file mode 100644
index 0000000..ac71386
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/AbstractInternalAdminServer.java
@@ -0,0 +1,116 @@
+/**
+ * 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.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerConfig;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerSetting;
+import org.apache.kerby.kerberos.kerb.identity.CacheableIdentityService;
+import org.apache.kerby.kerberos.kerb.identity.IdentityService;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.identity.backend.MemoryIdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+
+/**
+ * Abstract Kadmin admin implementation.
+ */
+public class AbstractInternalAdminServer implements InternalAdminServer {
+ private boolean started;
+ private final AdminServerConfig adminServerConfig;
+ private final BackendConfig backendConfig;
+ private final AdminServerSetting adminServerSetting;
+ private IdentityBackend backend;
+ private IdentityService identityService;
+
+ public AbstractInternalAdminServer(AdminServerSetting adminServerSetting) {
+ this.adminServerSetting = adminServerSetting;
+ this.adminServerConfig = adminServerSetting.getAdminServerConfig();
+ this.backendConfig = adminServerSetting.getBackendConfig();
+ }
+
+ @Override
+ public AdminServerSetting getSetting() {
+ return adminServerSetting;
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ protected String getServiceName() {
+ return adminServerConfig.getAdminServiceName();
+ }
+
+ protected IdentityService getIdentityService() {
+ if (identityService == null) {
+ if (backend instanceof MemoryIdentityBackend) { // Already in memory
+ identityService = backend;
+ } else {
+ identityService = new CacheableIdentityService(
+ backendConfig, backend);
+ }
+ }
+ return identityService;
+ }
+
+ @Override
+ public void init() throws KrbException {
+ backend = KdcUtil.getBackend(backendConfig);
+ }
+
+ @Override
+ public void start() throws KrbException {
+ try {
+ doStart();
+ } catch (Exception e) {
+ throw new KrbException("Failed to start " + getServiceName(), e);
+ }
+
+ started = true;
+ }
+
+ public boolean enableDebug() {
+ return adminServerConfig.enableDebug();
+ }
+
+ @Override
+ public IdentityBackend getIdentityBackend() {
+ return backend;
+ }
+
+ protected void doStart() throws Exception {
+ backend.start();
+ }
+
+ public void stop() throws KrbException {
+ try {
+ doStop();
+ } catch (Exception e) {
+ throw new KrbException("Failed to stop " + getServiceName(), e);
+ }
+
+ started = false;
+ }
+
+ protected void doStop() throws Exception {
+ backend.stop();
+ }
+}
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/DefaultAdminServerHandler.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/DefaultAdminServerHandler.java
new file mode 100644
index 0000000..1dbb017
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/DefaultAdminServerHandler.java
@@ -0,0 +1,199 @@
+/**
+ * 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.impl;
+
+import org.apache.kerby.kerberos.kerb.admin.AuthUtil;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerContext;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerHandler;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslServer;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.SocketTimeoutException;
+import java.nio.ByteBuffer;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+public class DefaultAdminServerHandler extends AdminServerHandler implements Runnable {
+ private static Logger logger = LoggerFactory.getLogger(DefaultAdminServerHandler.class);
+ private final KrbTransport transport;
+ private static boolean sasl = false;
+ private AdminServerContext adminServerContext;
+
+ public DefaultAdminServerHandler(AdminServerContext adminServerContext, KrbTransport transport) {
+ super(adminServerContext);
+ this.transport = transport;
+ this.adminServerContext = adminServerContext;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ if (!sasl) {
+ logger.info("Doing the sasl negotiation !!!");
+ try {
+ saslNegotiation();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ } else {
+ ByteBuffer message = transport.receiveMessage();
+ if (message == null) {
+ logger.debug("No valid request recved. Disconnect actively");
+ transport.release();
+ break;
+ }
+ handleMessage(message);
+ }
+ } catch (IOException e) {
+ transport.release();
+ logger.debug("Transport or decoding error occurred, "
+ + "disconnecting abnormally", e);
+ break;
+ }
+ }
+ }
+
+ protected void handleMessage(ByteBuffer message) {
+ InetAddress clientAddress = transport.getRemoteAddress();
+
+ try {
+ ByteBuffer adminResponse = handleMessage(message, clientAddress);
+ transport.sendMessage(adminResponse);
+ } catch (Exception e) {
+ transport.release();
+ logger.error("Error occured while processing request:", e);
+ }
+ }
+
+ private void saslNegotiation() throws Exception {
+
+ File keytabFile = new File(adminServerContext.getConfig().getKeyTabFile());
+ String principal = adminServerContext.getConfig().getProtocol() + "/"
+ + adminServerContext.getConfig().getAdminHost();
+
+ Subject subject = AuthUtil.loginUsingKeytab(principal, keytabFile);
+ Subject.doAs(subject, new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ try {
+ ByteBuffer message = null;
+ try {
+ message = transport.receiveMessage();
+ } catch (SocketTimeoutException e) {
+ // ignore time out
+ return null;
+ }
+
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put(Sasl.QOP, "auth-conf");
+ props.put(Sasl.SERVER_AUTH, "true");
+
+ String protocol = adminServerContext.getConfig().getProtocol();
+ String serverName = adminServerContext.getConfig().getServerName();
+ CallbackHandler callbackHandler = new SaslGssCallbackHandler();
+ SaslServer ss = Sasl.createSaslServer("GSSAPI",
+ protocol, serverName, props, callbackHandler);
+
+ if (ss == null) {
+ throw new Exception("Unable to find server implementation for: GSSAPI");
+ }
+
+ while (!ss.isComplete()) {
+ int scComplete = message.getInt();
+ if (scComplete == 0) {
+ System.out.println("success!!!");
+ sasl = true;
+ break;
+ }
+ sendMessage(message, ss);
+ if (!ss.isComplete()) {
+ logger.info("Waiting receive message");
+ message = transport.receiveMessage();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ });
+
+ }
+
+ private void sendMessage(ByteBuffer message, SaslServer ss) throws IOException {
+
+ byte[] arr = new byte[message.remaining()];
+ message.get(arr);
+ byte[] challenge = ss.evaluateResponse(arr);
+
+ // 4 is the head to go through network
+ ByteBuffer buffer = ByteBuffer.allocate(challenge.length + 8);
+ buffer.putInt(challenge.length + 4);
+ int ssComplete = ss.isComplete() ? 0 : 1;
+ buffer.putInt(ssComplete);
+ buffer.put(challenge);
+ buffer.flip();
+ transport.sendMessage(buffer);
+ }
+
+ private static class SaslGssCallbackHandler implements CallbackHandler {
+
+ @Override
+ public void handle(Callback[] callbacks) throws
+ UnsupportedCallbackException {
+ AuthorizeCallback ac = null;
+ for (Callback callback : callbacks) {
+ if (callback instanceof AuthorizeCallback) {
+ ac = (AuthorizeCallback) callback;
+ } else {
+ throw new UnsupportedCallbackException(callback,
+ "Unrecognized SASL GSSAPI Callback");
+ }
+ }
+ if (ac != null) {
+ String authid = ac.getAuthenticationID();
+ String authzid = ac.getAuthorizationID();
+ if (authid.equals(authzid)) {
+ ac.setAuthorized(true);
+ } else {
+ ac.setAuthorized(false);
+ }
+ if (ac.isAuthorized()) {
+ // System.out.println("SASL server GSSAPI callback: setting "
+ //+ "canonicalized client ID: " + authzid);
+ ac.setAuthorizedID(authzid);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/DefaultInternalAdminServerImpl.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/DefaultInternalAdminServerImpl.java
new file mode 100644
index 0000000..4234481
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/DefaultInternalAdminServerImpl.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.kadmin.impl;
+
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerContext;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerSetting;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerUtil;
+import org.apache.kerby.kerberos.kerb.transport.KdcNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * A default admin admin implementation.
+ */
+public class DefaultInternalAdminServerImpl extends AbstractInternalAdminServer {
+ private ExecutorService executor;
+ private AdminServerContext adminContext;
+ private KdcNetwork network;
+
+ public DefaultInternalAdminServerImpl(AdminServerSetting adminSetting) {
+ super(adminSetting);
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+
+ prepareHandler();
+
+ executor = Executors.newCachedThreadPool();
+
+ network = new KdcNetwork() {
+ @Override
+ protected void onNewTransport(KrbTransport transport) {
+ DefaultAdminServerHandler kdcHandler =
+ new DefaultAdminServerHandler(adminContext, transport);
+ executor.execute(kdcHandler);
+ }
+ };
+
+ network.init();
+ TransportPair tpair = AdminServerUtil.getTransportPair(getSetting());
+ network.listen(tpair);
+ network.start();
+ }
+
+ private void prepareHandler() {
+ adminContext = new AdminServerContext(getSetting());
+ adminContext.setIdentityService(getIdentityService());
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ super.doStop();
+
+ network.stop();
+
+ executor.shutdownNow();
+ }
+}
diff --git a/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/InternalAdminServer.java b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/InternalAdminServer.java
new file mode 100644
index 0000000..c0cde44
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kadmin/impl/InternalAdminServer.java
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.kerby.kerberos.kerb.admin.server.kadmin.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerSetting;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+
+/**
+ * An internal KDC admin interface.
+ */
+public interface InternalAdminServer {
+
+ /**
+ * Initialize.
+ * @throws KrbException e
+ */
+ void init() throws KrbException;
+
+ /**
+ * Start the KDC admin.
+ * @throws KrbException e
+ */
+ void start() throws KrbException;
+
+ /**
+ * Stop the KDC admin.
+ * @throws KrbException e
+ */
+ void stop() throws KrbException;
+
+ /**
+ * Get admin admin setting.
+ * @return setting
+ */
+ AdminServerSetting getSetting();
+
+ /**
+ * Get identity backend.
+ * @return IdentityBackend
+ */
+ IdentityBackend getIdentityBackend();
+}
diff --git a/kerby-kerb/kerb-admin-server/src/main/resources/adminServer.conf b/kerby-kerb/kerb-admin-server/src/main/resources/adminServer.conf
new file mode 100644
index 0000000..8c7a11e
--- /dev/null
+++ b/kerby-kerb/kerb-admin-server/src/main/resources/adminServer.conf
@@ -0,0 +1,20 @@
+#
+# 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 = TEST.COM
+admin_port = 65417
\ No newline at end of file
diff --git a/kerby-kerb/kerb-admin/pom.xml b/kerby-kerb/kerb-admin/pom.xml
index 2a50bce..e4d52de 100644
--- a/kerby-kerb/kerb-admin/pom.xml
+++ b/kerby-kerb/kerb-admin/pom.xml
@@ -37,5 +37,10 @@
<artifactId>kerb-util</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerby-xdr</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/AuthUtil.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/AuthUtil.java
new file mode 100644
index 0000000..68d03e7
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/AuthUtil.java
@@ -0,0 +1,141 @@
+/**
+ * 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;
+
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import java.io.File;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class AuthUtil {
+
+ public static final boolean ENABLE_DEBUG = true;
+
+ private static String getKrb5LoginModuleName() {
+ return System.getProperty("java.vendor").contains("IBM")
+ ? "com.ibm.security.auth.module.Krb5LoginModule"
+ : "com.sun.security.auth.module.Krb5LoginModule";
+ }
+
+ public static Subject loginUsingTicketCache(
+ String principal, File cacheFile) throws LoginException {
+ Set<Principal> principals = new HashSet<Principal>();
+ principals.add(new KerberosPrincipal(principal));
+
+ Subject subject = new Subject(false, principals,
+ new HashSet<Object>(), new HashSet<Object>());
+
+ Configuration conf = useTicketCache(principal, cacheFile);
+ String confName = "TicketCacheConf";
+ LoginContext loginContext = new LoginContext(confName, subject, null, conf);
+ loginContext.login();
+ return loginContext.getSubject();
+ }
+
+ public static Subject loginUsingKeytab(
+ String principal, File keytabFile) throws LoginException {
+ Set<Principal> principals = new HashSet<Principal>();
+ principals.add(new KerberosPrincipal(principal));
+
+ Subject subject = new Subject(false, principals,
+ new HashSet<Object>(), new HashSet<Object>());
+
+ Configuration conf = useKeytab(principal, keytabFile);
+ String confName = "KeytabConf";
+ LoginContext loginContext = new LoginContext(confName, subject, null, conf);
+ loginContext.login();
+ return loginContext.getSubject();
+ }
+
+ public static Configuration useTicketCache(String principal,
+ File credentialFile) {
+ return new TicketCacheJaasConf(principal, credentialFile);
+ }
+
+ public static Configuration useKeytab(String principal, File keytabFile) {
+ return new KeytabJaasConf(principal, keytabFile);
+ }
+
+ static class TicketCacheJaasConf extends Configuration {
+ private String principal;
+ private File clientCredentialFile;
+
+ TicketCacheJaasConf(String principal, File clientCredentialFile) {
+ this.principal = principal;
+ this.clientCredentialFile = clientCredentialFile;
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, String> options = new HashMap<String, String>();
+ options.put("principal", principal);
+ options.put("storeKey", "false");
+ options.put("doNotPrompt", "false");
+ options.put("useTicketCache", "true");
+ options.put("renewTGT", "true");
+ options.put("refreshKrb5Config", "true");
+ options.put("isInitiator", "true");
+ options.put("ticketCache", clientCredentialFile.getAbsolutePath());
+ options.put("debug", String.valueOf(ENABLE_DEBUG));
+
+ return new AppConfigurationEntry[]{
+ new AppConfigurationEntry(getKrb5LoginModuleName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options)};
+ }
+ }
+
+ static class KeytabJaasConf extends Configuration {
+ private String principal;
+ private File keytabFile;
+
+ KeytabJaasConf(String principal, File keytab) {
+ this.principal = principal;
+ this.keytabFile = keytab;
+ }
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, String> options = new HashMap<String, String>();
+ options.put("keyTab", keytabFile.getAbsolutePath());
+ options.put("principal", principal);
+ options.put("useKeyTab", "true");
+ options.put("storeKey", "true");
+ options.put("doNotPrompt", "true");
+ options.put("renewTGT", "false");
+ options.put("refreshKrb5Config", "true");
+ options.put("isInitiator", "true");
+ options.put("debug", String.valueOf(ENABLE_DEBUG));
+
+ return new AppConfigurationEntry[]{
+ new AppConfigurationEntry(getKrb5LoginModuleName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options)};
+ }
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminServer.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminServer.java
deleted file mode 100644
index 933accf..0000000
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminServer.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.admin;
-
-import org.apache.kerby.KOptions;
-import org.apache.kerby.kerberos.kerb.KrbException;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Server side admin facilities for remote, similar to MIT kadmind service.
- * It uses GSSAPI and XDR to communicate with remote client/kadmin to receive
- * and perform the requested operations. In this server side, it simply leverages
- * LocalKadmin to perform the real work.
- *
- * TO BE IMPLEMENTED.
- */
-public class KadminServer implements Kadmin {
- //private LocalKadmin localKadmin;
-
- @Override
- public String getKadminPrincipal() {
- return null;
- }
-
- @Override
- public void addPrincipal(String principal) throws KrbException {
-
- }
-
- @Override
- public void addPrincipal(String principal,
- KOptions kOptions) throws KrbException {
-
- }
-
- @Override
- public void addPrincipal(String principal,
- String password) throws KrbException {
-
- }
-
- @Override
- public void addPrincipal(String principal, String password,
- KOptions kOptions) throws KrbException {
-
- }
-
- @Override
- public void exportKeytab(File keytabFile,
- String principal) throws KrbException {
-
- }
-
- @Override
- public void exportKeytab(File keytabFile,
- List<String> principals) throws KrbException {
-
- }
-
- @Override
- public void exportKeytab(File keytabFile) throws KrbException {
-
- }
-
- @Override
- public void removeKeytabEntriesOf(File keytabFile,
- String principal) throws KrbException {
-
- }
-
- @Override
- public void removeKeytabEntriesOf(File keytabFile, String principal,
- int kvno) throws KrbException {
-
- }
-
- @Override
- public void removeOldKeytabEntriesOf(File keytabFile,
- String principal) throws KrbException {
-
- }
-
- @Override
- public void deletePrincipal(String principal) throws KrbException {
-
- }
-
- @Override
- public void modifyPrincipal(String principal,
- KOptions kOptions) throws KrbException {
-
- }
-
- @Override
- public void renamePrincipal(String oldPrincipalName,
- String newPrincipalName) throws KrbException {
-
- }
-
- @Override
- public List<String> getPrincipals() throws KrbException {
- return null;
- }
-
- @Override
- public List<String> getPrincipals(String globString) throws KrbException {
- return null;
- }
-
- @Override
- public void changePassword(String principal,
- String newPassword) throws KrbException {
-
- }
-
- @Override
- public void updateKeys(String principal) throws KrbException {
-
- }
-
- @Override
- public void release() throws KrbException {
-
- }
-}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/Krb5Conf.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/Krb5Conf.java
new file mode 100644
index 0000000..9e3b3cf
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/Krb5Conf.java
@@ -0,0 +1,86 @@
+/**
+ * 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;
+
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.util.IOUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Generate krb5 file using given kdc server settings.
+ */
+public class Krb5Conf {
+ public static final String KRB5_CONF = "java.security.krb5.conf";
+ private static final String KRB5_CONF_FILE = "krb5.conf";
+ private File confDir;
+ private KdcConfig kdcConfig;
+
+ public Krb5Conf(File confDir, KdcConfig kdcConfig) {
+ this.confDir = confDir;
+ this.kdcConfig = kdcConfig;
+ }
+
+ public void initKrb5conf() throws IOException {
+ File confFile = generateConfFile();
+ System.setProperty(KRB5_CONF, confFile.getAbsolutePath());
+ }
+
+ // Read in krb5.conf and substitute in the correct port
+ private File generateConfFile() throws IOException {
+
+ String resourcePath = kdcConfig.allowUdp() ? "/krb5_udp.conf" : "/krb5.conf";
+ InputStream templateResource = getClass().getResourceAsStream(resourcePath);
+
+ String templateContent = IOUtil.readInput(templateResource);
+
+ String content = templateContent;
+
+ content = content.replaceAll("_REALM_", "" + kdcConfig.getKdcRealm());
+
+ int kdcPort = kdcConfig.allowUdp() ? kdcConfig.getKdcUdpPort()
+ : kdcConfig.getKdcTcpPort();
+ content = content.replaceAll("_KDC_PORT_",
+ String.valueOf(kdcPort));
+
+ if (kdcConfig.allowTcp()) {
+ content = content.replaceAll("#_KDC_TCP_PORT_", "kdc_tcp_port = " + kdcConfig.getKdcTcpPort());
+ }
+ if (kdcConfig.allowUdp()) {
+ content = content.replaceAll("#_KDC_UDP_PORT_", "kdc_udp_port = " + kdcConfig.getKdcUdpPort());
+ }
+
+ int udpLimit = kdcConfig.allowUdp() ? 4096 : 1;
+ content = content.replaceAll("_UDP_LIMIT_", String.valueOf(udpLimit));
+
+ File confFile = new File(confDir, KRB5_CONF_FILE);
+ if (confFile.exists()) {
+ boolean delete = confFile.delete();
+ if (!delete) {
+ throw new RuntimeException("File delete error!");
+ }
+ }
+ IOUtil.writeFile(content, confFile);
+
+ return confFile;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java
new file mode 100644
index 0000000..27a8da2
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteAdminClientTool.java
@@ -0,0 +1,263 @@
+/**
+ * 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;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminConfig;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminUtil;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteAddPrincipalCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteDeletePrincipalCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteGetprincsCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemotePrintUsageCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteRenamePrincipalCommand;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+import org.apache.kerby.util.OSUtil;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * Command use of remote admin
+ */
+public class RemoteAdminClientTool {
+ private static final byte[] EMPTY = new byte[0];
+ private static KrbTransport transport;
+ private static final String PROMPT = RemoteAdminClientTool.class.getSimpleName() + ".local:";
+ private static final String USAGE = (OSUtil.isWindows()
+ ? "Usage: bin\\remote-admin-client.cmd" : "Usage: sh bin/remote-admin-client.sh")
+ + " <conf-file>\n"
+ + "\tExample:\n"
+ + "\t\t"
+ + (OSUtil.isWindows()
+ ? "bin\\remote-admin-client.cmd" : "sh bin/remote-admin-client.sh")
+ + " conf\n";
+
+ private static final String LEGAL_COMMANDS = "Available commands are: "
+ + "\n"
+ + "add_principal, addprinc\n"
+ + " Add principal\n"
+ + "delete_principal, delprinc\n"
+ + " Delete principal\n"
+ + "rename_principal, renprinc\n"
+ + " Rename principal\n"
+ + "listprincs\n"
+ + " List principals\n";
+
+ public static void main(String[] args) throws Exception {
+ AdminClient adminClient;
+
+ if (args.length < 1) {
+ System.err.println(USAGE);
+ System.exit(1);
+ }
+
+ String confDirPath = args[0];
+
+ File confFile = new File(confDirPath, "adminClient.conf");
+
+ final AdminConfig adminConfig = new AdminConfig();
+ adminConfig.addKrb5Config(confFile);
+
+ KdcConfig tmpKdcConfig = KdcUtil.getKdcConfig(new File(confDirPath));
+ if (tmpKdcConfig == null) {
+ tmpKdcConfig = new KdcConfig();
+ }
+
+ try {
+ Krb5Conf krb5Conf = new Krb5Conf(new File(confDirPath), tmpKdcConfig);
+ krb5Conf.initKrb5conf();
+ } catch (IOException e) {
+ throw new KrbException("Failed to make krb5.conf", e);
+ }
+
+ adminClient = new AdminClient(adminConfig);
+
+ File keytabFile = new File(adminConfig.getKeyTabFile());
+ if (keytabFile == null || !keytabFile.exists()) {
+ System.err.println("Need the valid keytab file value in conf file.");
+ return;
+ }
+
+ String adminRealm = adminConfig.getAdminRealm();
+
+ adminClient.setAdminRealm(adminRealm);
+ adminClient.setAllowTcp(true);
+ adminClient.setAllowUdp(false);
+ adminClient.setAdminTcpPort(adminConfig.getAdminPort());
+
+ adminClient.init();
+ System.out.println("admin init successful");
+
+ TransportPair tpair = null;
+ try {
+ tpair = AdminUtil.getTransportPair(adminClient.getSetting());
+ } catch (KrbException e) {
+ e.printStackTrace();
+ }
+ KrbNetwork network = new KrbNetwork();
+ network.setSocketTimeout(adminClient.getSetting().getTimeout());
+
+ try {
+ transport = network.connect(tpair);
+ } catch (IOException e) {
+ throw new KrbException("Failed to create transport", e);
+ }
+
+ String adminPrincipal = KrbUtil.makeKadminPrincipal(
+ adminClient.getSetting().getKdcRealm()).getName();
+ Subject subject = null;
+ try {
+ subject = AuthUtil.loginUsingKeytab(adminPrincipal,
+ new File(adminConfig.getKeyTabFile()));
+ } catch (LoginException e) {
+ e.printStackTrace();
+ }
+ Subject.doAs(subject, new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ try {
+
+ Map<String, String> props = new HashMap<String, String>();
+ props.put(Sasl.QOP, "auth-conf");
+ props.put(Sasl.SERVER_AUTH, "true");
+ SaslClient saslClient = null;
+ try {
+ String protocol = adminConfig.getProtocol();
+ String serverName = adminConfig.getServerName();
+ saslClient = Sasl.createSaslClient(new String[]{"GSSAPI"}, null,
+ protocol, serverName, props, null);
+ } catch (SaslException e) {
+ e.printStackTrace();
+ }
+ if (saslClient == null) {
+ throw new KrbException("Unable to find client implementation for: GSSAPI");
+ }
+ byte[] response = new byte[0];
+ try {
+ response = saslClient.hasInitialResponse()
+ ? saslClient.evaluateChallenge(EMPTY) : EMPTY;
+ } catch (SaslException e) {
+ e.printStackTrace();
+ }
+
+ sendMessage(response, saslClient);
+
+ ByteBuffer message = transport.receiveMessage();
+
+ while (!saslClient.isComplete()) {
+ int ssComplete = message.getInt();
+ if (ssComplete == 0) {
+ System.out.println("Sasl Server completed");
+ }
+ byte[] arr = new byte[message.remaining()];
+ message.get(arr);
+ byte[] challenge = saslClient.evaluateChallenge(arr);
+
+ sendMessage(challenge, saslClient);
+
+ if (!saslClient.isComplete()) {
+ message = transport.receiveMessage();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ });
+
+ System.out.println("enter \"command\" to see legal commands.");
+
+ try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
+ String input = scanner.nextLine();
+
+ while (!(input.equals("quit") || input.equals("exit") || input.equals("q"))) {
+ excute(adminClient, input);
+ System.out.print(PROMPT);
+ input = scanner.nextLine();
+ }
+ }
+ }
+
+ private static void sendMessage(byte[] challenge, SaslClient saslClient)
+ throws SaslException {
+
+ // 4 is the head to go through network
+ ByteBuffer buffer = ByteBuffer.allocate(challenge.length + 8);
+ buffer.putInt(challenge.length + 4);
+ int scComplete = saslClient.isComplete() ? 0 : 1;
+
+ buffer.putInt(scComplete);
+ buffer.put(challenge);
+ buffer.flip();
+
+ try {
+ transport.sendMessage(buffer);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static void excute(AdminClient adminClient, String input) throws KrbException {
+ input = input.trim();
+ if (input.startsWith("command")) {
+ System.out.println(LEGAL_COMMANDS);
+ return;
+ }
+
+ RemoteCommand executor = null;
+
+ if (input.startsWith("add_principal")
+ || input.startsWith("addprinc")) {
+ executor = new RemoteAddPrincipalCommand(adminClient);
+ } else if (input.startsWith("delete_principal")
+ || input.startsWith("delprinc")) {
+ executor = new RemoteDeletePrincipalCommand(adminClient);
+ } else if (input.startsWith("rename_principal")
+ || input.startsWith("renprinc")) {
+ executor = new RemoteRenamePrincipalCommand(adminClient);
+ } else if (input.startsWith("list_principals")) {
+ executor = new RemoteGetprincsCommand(adminClient);
+ } else if (input.startsWith("listprincs")) {
+ executor = new RemotePrintUsageCommand();
+ } else {
+ System.out.println(LEGAL_COMMANDS);
+ return;
+ }
+ executor.execute(input);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java
deleted file mode 100644
index 16115d8..0000000
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/RemoteKadminImpl.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.kerby.kerberos.kerb.admin;
-
-import org.apache.kerby.KOptions;
-import org.apache.kerby.kerberos.kerb.KrbException;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Server side admin facilities from remote, similar to MIT Kadmin remote mode.
- * It uses GSSAPI and XDR to communicate with remote KDC/kadmind to do the
- * requested operations. In the client side, it simply wraps and sends the
- * request info to the server kadmind side, and then unwraps the response for
- * the operation result.
- *
- * TO BE IMPLEMENTED.
- */
-public class RemoteKadminImpl implements Kadmin {
-
- @Override
- public String getKadminPrincipal() {
- return null;
- }
-
- @Override
- public void addPrincipal(String principal) throws KrbException {
-
- }
-
- @Override
- public void addPrincipal(String principal,
- KOptions kOptions) throws KrbException {
-
- }
-
- @Override
- public void addPrincipal(String principal,
- String password) throws KrbException {
-
- }
-
- @Override
- public void addPrincipal(String principal, String password,
- KOptions kOptions) throws KrbException {
-
- }
-
- @Override
- public void exportKeytab(File keytabFile,
- String principal) throws KrbException {
-
- }
-
- @Override
- public void exportKeytab(File keytabFile,
- List<String> principals) throws KrbException {
-
- }
-
- @Override
- public void exportKeytab(File keytabFile) throws KrbException {
-
- }
-
- @Override
- public void removeKeytabEntriesOf(File keytabFile,
- String principal) throws KrbException {
-
- }
-
- @Override
- public void removeKeytabEntriesOf(File keytabFile, String principal,
- int kvno) throws KrbException {
-
- }
-
- @Override
- public void removeOldKeytabEntriesOf(File keytabFile,
- String principal) throws KrbException {
-
- }
-
- @Override
- public void deletePrincipal(String principal) throws KrbException {
-
- }
-
- @Override
- public void modifyPrincipal(String principal,
- KOptions kOptions) throws KrbException {
-
- }
-
- @Override
- public void renamePrincipal(String oldPrincipalName,
- String newPrincipalName) throws KrbException {
-
- }
-
- @Override
- public List<String> getPrincipals() throws KrbException {
- return null;
- }
-
- @Override
- public List<String> getPrincipals(String globString) throws KrbException {
- return null;
- }
-
- @Override
- public void changePassword(String principal,
- String newPassword) throws KrbException {
-
- }
-
- @Override
- public void updateKeys(String principal) throws KrbException {
-
- }
-
- @Override
- public void release() throws KrbException {
-
- }
-}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/Kadmin.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java
similarity index 98%
rename from kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/Kadmin.java
rename to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java
index 594ff6b..8f95b37 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/Kadmin.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/Kadmin.java
@@ -17,7 +17,7 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.kadmin;
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java
similarity index 97%
rename from kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
rename to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java
index 0c11fe7..f6caa87 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/KadminOption.java
@@ -17,7 +17,7 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.kadmin;
import org.apache.kerby.KOption;
import org.apache.kerby.KOptionInfo;
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/AdminHelper.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java
similarity index 98%
rename from kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/AdminHelper.java
rename to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java
index 62c38b6..f78ec45 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/AdminHelper.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java
@@ -17,16 +17,17 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.kadmin.local;
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
import org.apache.kerby.kerberos.kerb.keytab.Keytab;
import org.apache.kerby.kerberos.kerb.keytab.KeytabEntry;
-import org.apache.kerby.kerberos.kerb.type.KerberosTime;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
import java.io.File;
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.java
similarity index 90%
rename from kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java
rename to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.java
index d8d38f1..5fd2d0d 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadmin.java
@@ -17,9 +17,10 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.kadmin.local;
import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
@@ -29,9 +30,9 @@
* Server side admin facilities for local, similar to MIT kadmin local mode. It
* may be not accurate regarding 'local' because, if the identity backend itself
* is supported to be accessed from remote, it won't have to be remote; but if
- * not, then it must be local to the KDC server bounded with the local backend.
+ * not, then it must be local to the KDC admin bounded with the local backend.
*
- * Note, suitable with Kerby KdcServer based KDCs like Kerby KDC.
+ * Note, suitable with Kerby AdminServerImpl based KDCs like Kerby KDC.
*/
public interface LocalKadmin extends Kadmin {
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java
similarity index 92%
rename from kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java
rename to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java
index 9f0f89e..80fc10b 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/LocalKadminImpl.java
@@ -17,20 +17,21 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.kadmin.local;
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
-import org.apache.kerby.kerberos.kerb.common.KrbUtil;
-import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
-import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
import org.apache.kerby.kerberos.kerb.keytab.Keytab;
import org.apache.kerby.kerberos.kerb.server.KdcConfig;
import org.apache.kerby.kerberos.kerb.server.KdcSetting;
import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.server.ServerSetting;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,16 +45,16 @@
import java.util.regex.Pattern;
/**
- * The implementation of server side admin facilities for local mode.
+ * The implementation of admin side admin facilities for local mode.
*/
public class LocalKadminImpl implements LocalKadmin {
private static final Logger LOG = LoggerFactory.getLogger(LocalKadminImpl.class);
- private final KdcSetting kdcSetting;
+ private final ServerSetting serverSetting;
private final IdentityBackend backend;
/**
- * Construct with prepared KdcConfig and BackendConfig.
+ * Construct with prepared AdminServerConfig and BackendConfig.
*
* @param kdcConfig The kdc config
* @param backendConfig The backend config
@@ -62,7 +63,13 @@
public LocalKadminImpl(KdcConfig kdcConfig,
BackendConfig backendConfig) throws KrbException {
this.backend = KdcUtil.getBackend(backendConfig);
- this.kdcSetting = new KdcSetting(kdcConfig, backendConfig);
+ this.serverSetting = new KdcSetting(kdcConfig, backendConfig);
+ }
+
+ //
+ public LocalKadminImpl(ServerSetting serverSetting) throws KrbException {
+ this.backend = KdcUtil.getBackend(serverSetting.getBackendConfig());
+ this.serverSetting = serverSetting;
}
/**
@@ -82,19 +89,19 @@
tmpBackendConfig = new BackendConfig();
}
- this.kdcSetting = new KdcSetting(tmpKdcConfig, tmpBackendConfig);
+ this.serverSetting = new KdcSetting(tmpKdcConfig, tmpBackendConfig);
backend = KdcUtil.getBackend(tmpBackendConfig);
}
/**
- * Construct with prepared KdcSetting and Backend.
+ * Construct with prepared AdminServerSetting and Backend.
*
* @param kdcSetting The kdc setting
* @param backend The identity backend
*/
public LocalKadminImpl(KdcSetting kdcSetting, IdentityBackend backend) {
- this.kdcSetting = kdcSetting;
+ this.serverSetting = kdcSetting;
this.backend = backend;
}
@@ -102,12 +109,12 @@
* Get the tgs principal name.
*/
private String getTgsPrincipal() {
- return KrbUtil.makeTgsPrincipal(kdcSetting.getKdcRealm()).getName();
+ return KrbUtil.makeTgsPrincipal(serverSetting.getKdcRealm()).getName();
}
@Override
public String getKadminPrincipal() {
- return KrbUtil.makeKadminPrincipal(kdcSetting.getKdcRealm()).getName();
+ return KrbUtil.makeKadminPrincipal(serverSetting.getKdcRealm()).getName();
}
@Override
@@ -152,12 +159,12 @@
@Override
public KdcConfig getKdcConfig() {
- return kdcSetting.getKdcConfig();
+ return serverSetting.getKdcConfig();
}
@Override
public BackendConfig getBackendConfig() {
- return kdcSetting.getBackendConfig();
+ return serverSetting.getBackendConfig();
}
@Override
@@ -393,7 +400,7 @@
*/
private String fixPrincipal(String principal) {
if (!principal.contains("@")) {
- principal += "@" + kdcSetting.getKdcRealm();
+ principal += "@" + serverSetting.getKdcRealm();
}
return principal;
}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java
new file mode 100644
index 0000000..01c336d
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminClient.java
@@ -0,0 +1,204 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.DefaultInternalAdminClient;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.InternalAdminClient;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * A Admin client API for applications to interact with Admin Server
+ */
+public class AdminClient {
+
+ private final AdminConfig adminConfig;
+ private final KOptions commonOptions;
+ private final AdminSetting adminSetting;
+
+ private InternalAdminClient innerClient;
+
+ /**
+ * Default constructor.
+ * @throws KrbException e
+ */
+ public AdminClient() throws KrbException {
+ this.adminConfig = AdminUtil.getDefaultConfig();
+ this.commonOptions = new KOptions();
+ this.adminSetting = new AdminSetting(commonOptions, adminConfig);
+ }
+
+ /**
+ * Construct with prepared AdminConfig.
+ * @param adminConfig The krb config
+ */
+ public AdminClient(AdminConfig adminConfig) {
+ this.adminConfig = adminConfig;
+ this.commonOptions = new KOptions();
+ this.adminSetting = new AdminSetting(commonOptions, adminConfig);
+ }
+
+ /**
+ * Constructor with conf dir
+ * @param confDir The conf dir
+ * @throws KrbException e
+ */
+ public AdminClient(File confDir) throws KrbException {
+ this.commonOptions = new KOptions();
+ this.adminConfig = AdminUtil.getConfig(confDir);
+ this.adminSetting = new AdminSetting(commonOptions, adminConfig);
+ }
+
+ /**
+ * Constructor with prepared AdminClient.
+ * @param krbClient The krb client
+ */
+ public AdminClient(AdminClient krbClient) {
+ this.commonOptions = krbClient.commonOptions;
+ this.adminConfig = krbClient.adminConfig;
+ this.adminSetting = krbClient.adminSetting;
+ this.innerClient = krbClient.innerClient;
+ }
+
+ /**
+ * Set KDC realm for ticket request
+ * @param realm The realm
+ */
+ public void setAdminRealm(String realm) {
+ commonOptions.add(AdminOption.ADMIN_REALM, realm);
+ }
+
+ public void setKeyTabFile(File file) {
+ commonOptions.add(AdminOption.KEYTAB_FILE, file);
+ }
+
+ /**
+ * Set Admin Server host.
+ * @param kdcHost The kdc host
+ */
+ public void setKdcHost(String kdcHost) {
+ commonOptions.add(AdminOption.ADMIN_HOST, kdcHost);
+ }
+
+ /**
+ * Set Admin Server tcp port.
+ * @param kdcTcpPort The kdc tcp port
+ */
+ public void setAdminTcpPort(int kdcTcpPort) {
+ if (kdcTcpPort < 1) {
+ throw new IllegalArgumentException("Invalid port");
+ }
+ commonOptions.add(AdminOption.ADMIN_TCP_PORT, kdcTcpPort);
+ setAllowTcp(true);
+ }
+
+ /**
+ * Set to allow UDP or not.
+ * @param allowUdp true if allow udp
+ */
+ public void setAllowUdp(boolean allowUdp) {
+ commonOptions.add(AdminOption.ALLOW_UDP, allowUdp);
+ }
+
+ /**
+ * Set to allow TCP or not.
+ * @param allowTcp true if allow tcp
+ */
+ public void setAllowTcp(boolean allowTcp) {
+ commonOptions.add(AdminOption.ALLOW_TCP, allowTcp);
+ }
+
+ /**
+ * Set Admin Server udp port. Only makes sense when allowUdp is set.
+ * @param adminUdpPort The kdc udp port
+ */
+ public void setAdminUdpPort(int adminUdpPort) {
+ if (adminUdpPort < 1) {
+ throw new IllegalArgumentException("Invalid port");
+ }
+ commonOptions.add(AdminOption.ADMIN_UDP_PORT, adminUdpPort);
+ setAllowUdp(true);
+ }
+
+ /**
+ * Set time out for connection
+ * @param timeout in seconds
+ */
+ public void setTimeout(int timeout) {
+ commonOptions.add(AdminOption.CONN_TIMEOUT, timeout);
+ }
+
+ /**
+ * Init the client.
+ * @throws KrbException e
+ */
+ public void init() throws KrbException {
+ innerClient = new DefaultInternalAdminClient(adminSetting);
+ innerClient.init();
+ }
+
+ /**
+ * Get krb client settings from options and configs.
+ * @return setting
+ */
+ public AdminSetting getSetting() {
+ return adminSetting;
+ }
+
+ public AdminConfig getAdminConfig() {
+ return adminConfig;
+ }
+
+ public void requestAddPrincipal(String principal) throws KrbException {
+ Kadmin remote = new RemoteKadminImpl(innerClient);
+ remote.addPrincipal(principal);
+ }
+
+ public void requestAddPrincipal(String principal, String password) throws KrbException {
+ Kadmin remote = new RemoteKadminImpl(innerClient);
+ remote.addPrincipal(principal, password);
+ }
+
+ public void requestDeletePrincipal(String principal) throws KrbException {
+ Kadmin remote = new RemoteKadminImpl(innerClient);
+ remote.deletePrincipal(principal);
+ }
+
+ public void requestRenamePrincipal(String oldPrincipal, String newPrincipal) throws KrbException {
+ Kadmin remote = new RemoteKadminImpl(innerClient);
+ remote.renamePrincipal(oldPrincipal, newPrincipal);
+ }
+
+ public List<String> requestGetprincs() throws KrbException {
+ Kadmin remote = new RemoteKadminImpl(innerClient);
+ List<String> principalLists = remote.getPrincipals();
+ return principalLists;
+ }
+
+ public List<String> requestGetprincsWithExp(String exp) throws KrbException {
+ Kadmin remote = new RemoteKadminImpl(innerClient);
+ List<String> principalLists = remote.getPrincipals(exp);
+ return principalLists;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.java
new file mode 100644
index 0000000..e2e6443
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfig.java
@@ -0,0 +1,132 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb client side configuration API.
+ */
+public class AdminConfig extends Krb5Conf {
+ private static final String LIBDEFAULT = "libdefaults";
+
+ public boolean enableDebug() {
+ return getBoolean(AdminConfigKey.KRB_DEBUG, true, LIBDEFAULT);
+ }
+
+ /**
+ * Get KDC host name
+ *
+ * @return The kdc host
+ */
+ public String getAdminHost() {
+ return getString(
+ AdminConfigKey.ADMIN_HOST, true, LIBDEFAULT);
+ }
+
+ /**
+ * Get KDC port, as both TCP and UDP ports
+ *
+ * @return The kdc host
+ */
+ public int getAdminPort() {
+ Integer kdcPort = getInt(AdminConfigKey.ADMIN_PORT, true, LIBDEFAULT);
+ if (kdcPort != null) {
+ return kdcPort.intValue();
+ }
+ return -1;
+ }
+
+ /**
+ * Get KDC TCP port
+ *
+ * @return The kdc tcp port
+ */
+ public int getAdminTcpPort() {
+ Integer kdcPort = getInt(AdminConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT);
+ if (kdcPort != null && kdcPort > 0) {
+ return kdcPort.intValue();
+ }
+ return getAdminPort();
+ }
+
+ /**
+ * Is to allow UDP for KDC
+ *
+ * @return true to allow UDP, false otherwise
+ */
+ public boolean allowUdp() {
+ return getBoolean(AdminConfigKey.ADMIN_ALLOW_UDP, true, LIBDEFAULT)
+ || getInt(AdminConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT) != null
+ || getInt(AdminConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+ }
+
+ /**
+ * Is to allow TCP for KDC
+ *
+ * @return true to allow TCP, false otherwise
+ */
+ public boolean allowTcp() {
+ return getBoolean(AdminConfigKey.ADMIN_ALLOW_TCP, true, LIBDEFAULT)
+ || getInt(AdminConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT) != null
+ || getInt(AdminConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+ }
+
+ /**
+ * Get KDC UDP port
+ *
+ * @return The kdc udp port
+ */
+ public int getAdminUdpPort() {
+ Integer kdcPort = getInt(AdminConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT);
+ if (kdcPort != null && kdcPort > 0) {
+ return kdcPort.intValue();
+ }
+ return getAdminPort();
+ }
+
+ /**
+ * Get KDC realm.
+ * @return The kdc realm
+ */
+ public String getAdminRealm() {
+ String realm = getString(AdminConfigKey.ADMIN_REALM, false, LIBDEFAULT);
+ if (realm == null) {
+ realm = getString(AdminConfigKey.DEFAULT_REALM, false, LIBDEFAULT);
+ if (realm == null) {
+ realm = (String) AdminConfigKey.ADMIN_REALM.getDefaultValue();
+ }
+ }
+
+ return realm;
+ }
+
+ public String getKeyTabFile() {
+ return getString(AdminConfigKey.KEYTAB_FILE, true, LIBDEFAULT);
+ }
+
+ public String getProtocol() {
+ return getString(AdminConfigKey.PROTOCOL, true, LIBDEFAULT);
+ }
+
+ public String getServerName() {
+ return getString(AdminConfigKey.SERVER_NAME, true, LIBDEFAULT);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java
new file mode 100644
index 0000000..4227930
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminConfigKey.java
@@ -0,0 +1,58 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum AdminConfigKey implements ConfigKey {
+ KRB_DEBUG(true),
+ ADMIN_HOST("localhost"),
+ ADMIN_PORT(null),
+ ADMIN_ALLOW_UDP(false),
+ ADMIN_ALLOW_TCP(false),
+ ADMIN_UDP_PORT(null),
+ ADMIN_TCP_PORT(null),
+ ADMIN_DOMAIN("example.com"),
+ DEFAULT_REALM(null),
+ ADMIN_REALM("EXAMPLE.COM"),
+ KEYTAB_FILE,
+ PROTOCOL,
+ SERVER_NAME("localhost");
+
+ private Object defaultValue;
+
+ AdminConfigKey() {
+ this.defaultValue = null;
+ }
+
+ AdminConfigKey(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public String getPropertyKey() {
+ return name().toLowerCase();
+ }
+
+ @Override
+ public Object getDefaultValue() {
+ return this.defaultValue;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.java
new file mode 100644
index 0000000..67219a6
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminContext.java
@@ -0,0 +1,49 @@
+/**
+ * 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.kadmin.remote;
+
+public class AdminContext {
+
+ private AdminSetting adminSetting;
+
+ /**
+ * Init with krbsetting.
+ * @param adminSetting The krb setting
+ */
+ public void init(AdminSetting adminSetting) {
+ this.adminSetting = adminSetting;
+ }
+
+ /**
+ * Get krbsetting.
+ * @return The krb setting
+ */
+ public AdminSetting getAdminSetting() {
+ return adminSetting;
+ }
+
+ /**
+ * Get krbconfig.
+ * @return The krb config
+ */
+ public AdminConfig getConfig() {
+ return adminSetting.getAdminConfig();
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java
new file mode 100644
index 0000000..9debfdd
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminHandler.java
@@ -0,0 +1,162 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.AdminRequest;
+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.AdminReq;
+import org.apache.kerby.kerberos.kerb.admin.message.KadminCode;
+import org.apache.kerby.xdr.XdrFieldInfo;
+import org.apache.kerby.xdr.type.XdrStructType;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+public abstract class AdminHandler {
+
+ /**
+ * Init with krbcontext.
+ *
+ * @param context The krbcontext
+ */
+ public void init(AdminContext context) {
+
+ }
+
+ /**
+ * Handle the kdc request.
+ *
+ * @param adminRequest The admin request
+ * @throws KrbException e
+ */
+ public void handleRequest(AdminRequest adminRequest) throws KrbException {
+ adminRequest.process();
+ AdminReq adminReq = adminRequest.getAdminReq();
+ ByteBuffer requestMessage = KadminCode.encodeMessage(adminReq);
+ requestMessage.flip();
+
+ try {
+ sendMessage(adminRequest, requestMessage);
+ } catch (IOException e) {
+ throw new KrbException("Admin sends request message failed", e);
+ }
+
+ }
+
+ /**
+ * Process the response message from kdc.
+ *
+ * @param adminRequest The admin request
+ * @param responseMessage The message from kdc
+ * @throws KrbException e
+ */
+ public void onResponseMessage(AdminRequest adminRequest,
+ ByteBuffer responseMessage) throws KrbException {
+
+
+ XdrStructType decoded = new AdminMessageCode();
+ try {
+ decoded.decode(responseMessage);
+ } catch (IOException e) {
+ throw new KrbException("On response message failed.", e);
+ }
+ XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+ AdminMessageType type = (AdminMessageType) fieldInfos[0].getValue();
+
+ switch (type) {
+ case ADD_PRINCIPAL_REP:
+ if (adminRequest.getAdminReq().getAdminMessageType()
+ == AdminMessageType.ADD_PRINCIPAL_REQ) {
+ System.out.println((String) fieldInfos[2].getValue());
+ } else {
+ throw new KrbException("Response message type error: need "
+ + AdminMessageType.ADD_PRINCIPAL_REP);
+ }
+ break;
+ case DELETE_PRINCIPAL_REP:
+ if (adminRequest.getAdminReq().getAdminMessageType()
+ == AdminMessageType.DELETE_PRINCIPAL_REQ) {
+ System.out.println((String) fieldInfos[2].getValue());
+ } else {
+ throw new KrbException("Response message type error: need "
+ + AdminMessageType.DELETE_PRINCIPAL_REP);
+ }
+ break;
+ case RENAME_PRINCIPAL_REP:
+ if (adminRequest.getAdminReq().getAdminMessageType()
+ == AdminMessageType.RENAME_PRINCIPAL_REQ) {
+ System.out.println((String) fieldInfos[2].getValue());
+ } else {
+ throw new KrbException("Response message type error: need "
+ + AdminMessageType.RENAME_PRINCIPAL_REP);
+ }
+ break;
+ default:
+ throw new KrbException("Response message type error: " + type);
+ }
+ }
+
+ public List<String> onResponseMessageForList(AdminRequest adminRequest,
+ ByteBuffer responseMessage) throws KrbException {
+ List<String> princalsList = null;
+
+ XdrStructType decoded = new AdminMessageCode();
+ try {
+ decoded.decode(responseMessage);
+ } catch (IOException e) {
+ throw new KrbException("On response message failed.", e);
+ }
+ XdrFieldInfo[] fieldInfos = decoded.getValue().getXdrFieldInfos();
+ AdminMessageType type = (AdminMessageType) fieldInfos[0].getValue();
+
+ switch (type) {
+ case GET_PRINCS_REP:
+ if (adminRequest.getAdminReq().getAdminMessageType()
+ == AdminMessageType.GET_PRINCS_REQ) {
+ String[] temp = ((String) fieldInfos[2].getValue()).trim().split(" ");
+ princalsList = Arrays.asList(temp);
+ } else {
+ throw new KrbException("Response message type error: need "
+ + AdminMessageType.GET_PRINCS_REP);
+ }
+ break;
+ default:
+ throw new KrbException("Response message type error: " + type);
+ }
+
+ return princalsList;
+ }
+
+ /**
+ * Send message to kdc.
+ *
+ * @param adminRequest The admin request
+ * @param requestMessage The request message to kdc
+ * @throws IOException e
+ */
+ protected abstract void sendMessage(AdminRequest adminRequest,
+ ByteBuffer requestMessage) throws IOException;
+
+ protected abstract List<String> handleRequestForList(AdminRequest adminRequest) throws KrbException;
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java
new file mode 100644
index 0000000..fc2d45b
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminOption.java
@@ -0,0 +1,102 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * This defines all the options that come across the client side.
+ */
+public enum AdminOption implements KOption {
+ NONE(null),
+
+ ADMIN_REALM(new KOptionInfo("admin-realm", "kdc realm",
+ KOptionType.STR)),
+ ADMIN_HOST(new KOptionInfo("admin-host", "kdc host",
+ KOptionType.STR)),
+ ADMIN_TCP_PORT(new KOptionInfo("admin-tcp-port", "kdc tcp port",
+ KOptionType.INT)),
+ ALLOW_UDP(new KOptionInfo("allow-udp", "allow udp",
+ KOptionType.BOOL)),
+ ALLOW_TCP(new KOptionInfo("allow-tcp", "allow tcp",
+ KOptionType.BOOL)),
+ ADMIN_UDP_PORT(new KOptionInfo("admin-udp-port", "kdc udp port",
+ KOptionType.INT)),
+ CONN_TIMEOUT(new KOptionInfo("conn-timeout", "connection timeout",
+ KOptionType.INT)),
+
+ LIFE_TIME(new KOptionInfo("life-time", "life time",
+ KOptionType.INT)),
+ START_TIME(new KOptionInfo("start-time", "start time",
+ KOptionType.INT)),
+ RENEWABLE_TIME(new KOptionInfo("renewable_lifetime", "renewable lifetime",
+ KOptionType.INT)),
+ INCLUDE_ADDRESSES(new KOptionInfo("include_addresses",
+ "include addresses")),
+ AS_ENTERPRISE_PN(new KOptionInfo("as-enterprise-pn",
+ "client is enterprise principal name")),
+ CLIENT_PRINCIPAL(new KOptionInfo("client-principal", "Client principal",
+ KOptionType.STR)),
+
+ USE_PASSWD(new KOptionInfo("using-password", "using password")),
+ USER_PASSWD(new KOptionInfo("user-passwd", "User plain password")),
+
+ USE_KEYTAB(new KOptionInfo("use-keytab", "use keytab")),
+ USE_DFT_KEYTAB(new KOptionInfo("use-dft-keytab", "use default client keytab (with -k)")),
+ KEYTAB_FILE(new KOptionInfo("keytab-file", "filename of keytab to use",
+ KOptionType.FILE)),
+
+ KRB5_CACHE(new KOptionInfo("krb5-cache", "K5 cache name",
+ KOptionType.FILE)),
+ SERVICE_PRINCIPAL(new KOptionInfo("service-principal", "service principal",
+ KOptionType.STR)),
+ SERVER_PRINCIPAL(new KOptionInfo("admin-principal", "admin principal",
+ KOptionType.STR)),
+ ARMOR_CACHE(new KOptionInfo("armor-cache", "armor credential cache",
+ KOptionType.STR)),
+ USE_TGT(new KOptionInfo("use-tgt", "use tgt to get service ticket",
+ KOptionType.OBJ)),
+ CONF_DIR(new KOptionInfo("-conf", "conf dir", KOptionType.DIR));
+
+ private final KOptionInfo optionInfo;
+
+ AdminOption(KOptionInfo optionInfo) {
+ this.optionInfo = optionInfo;
+ }
+
+ @Override
+ public KOptionInfo getOptionInfo() {
+ return optionInfo;
+ }
+
+ public static AdminOption fromOptionName(String optionName) {
+ if (optionName != null) {
+ for (AdminOption ko : values()) {
+ if (ko.optionInfo != null
+ && ko.optionInfo.getName().equals(optionName)) {
+ return ko;
+ }
+ }
+ }
+ return NONE;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java
new file mode 100644
index 0000000..1e519ea
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminSetting.java
@@ -0,0 +1,129 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Admin client setting that combines common options and client config.
+ */
+public class AdminSetting {
+ private final KOptions commonOptions;
+ private final AdminConfig adminConfig;
+
+ public AdminSetting(KOptions commonOptions, AdminConfig config) {
+ this.commonOptions = commonOptions;
+ this.adminConfig = config;
+ }
+
+ public AdminSetting(AdminConfig config) {
+ this.commonOptions = new KOptions();
+ this.adminConfig = config;
+ }
+
+ public AdminConfig getAdminConfig() {
+ return adminConfig;
+ }
+
+ public String getKdcRealm() {
+ String kdcRealm = commonOptions.getStringOption(AdminOption.ADMIN_REALM);
+ if (kdcRealm == null || kdcRealm.isEmpty()) {
+ kdcRealm = adminConfig.getAdminRealm();
+ }
+ return kdcRealm;
+ }
+
+ public String getKdcHost() {
+ String kdcHost = commonOptions.getStringOption(AdminOption.ADMIN_HOST);
+ if (kdcHost == null) {
+ return adminConfig.getAdminHost();
+ }
+ return kdcHost;
+ }
+
+ /**
+ * Check kdc tcp setting and see if any bad.
+ * @return valid tcp port or -1 if not allowTcp
+ * @throws KrbException e
+ */
+ public int checkGetKdcTcpPort() throws KrbException {
+ if (allowTcp()) {
+ int kdcPort = getKdcTcpPort();
+ if (kdcPort < 1) {
+ throw new KrbException("KDC tcp port isn't set or configured");
+ }
+ return kdcPort;
+ }
+ return -1;
+ }
+
+ /**
+ * Check kdc udp setting and see if any bad.
+ * @return valid udp port or -1 if not allowUdp
+ * @throws KrbException e
+ */
+ public int checkGetKdcUdpPort() throws KrbException {
+ if (allowUdp()) {
+ int kdcPort = getKdcUdpPort();
+ if (kdcPort < 1) {
+ throw new KrbException("KDC udp port isn't set or configured");
+ }
+ return kdcPort;
+ }
+ return -1;
+ }
+
+ public int getKdcTcpPort() {
+ int tcpPort = commonOptions.getIntegerOption(AdminOption.ADMIN_TCP_PORT);
+ if (tcpPort > 0) {
+ return tcpPort;
+ }
+ return adminConfig.getAdminTcpPort();
+ }
+
+ public boolean allowUdp() {
+ Boolean allowUdp = commonOptions.getBooleanOption(
+ AdminOption.ALLOW_UDP, adminConfig.allowUdp());
+ return allowUdp;
+ }
+
+ public boolean allowTcp() {
+ Boolean allowTcp = commonOptions.getBooleanOption(
+ AdminOption.ALLOW_TCP, adminConfig.allowTcp());
+ return allowTcp;
+ }
+
+ public int getKdcUdpPort() {
+ int udpPort = commonOptions.getIntegerOption(AdminOption.ADMIN_UDP_PORT);
+ if (udpPort > 0) {
+ return udpPort;
+ }
+ return adminConfig.getAdminUdpPort();
+ }
+
+ public int getTimeout() {
+ int timeout = commonOptions.getIntegerOption(AdminOption.CONN_TIMEOUT);
+ if (timeout > 0) {
+ return timeout;
+ }
+ return 1000; // by default
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminUtil.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminUtil.java
new file mode 100644
index 0000000..00cc409
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/AdminUtil.java
@@ -0,0 +1,127 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Map;
+
+public final class AdminUtil {
+ private AdminUtil() { }
+
+ private static final String KRB5_FILE_NAME = "krb5.conf";
+ private static final String KRB5_ENV_NAME = "KRB5_CONFIG";
+
+ /**
+ * Load krb5.conf from specified conf dir.
+ * @param confDir The conf dir
+ * @return AdminConfig
+ * @throws KrbException e
+ */
+ public static AdminConfig getConfig(File confDir) throws KrbException {
+ File confFile = new File(confDir, KRB5_FILE_NAME);
+ if (!confFile.exists()) {
+ throw new KrbException(KRB5_FILE_NAME + " not found");
+ }
+
+ if (confFile != null && confFile.exists()) {
+ AdminConfig adminConfig = new AdminConfig();
+ try {
+ adminConfig.addKrb5Config(confFile);
+ return adminConfig;
+ } catch (IOException e) {
+ throw new KrbException("Failed to load krb config "
+ + confFile.getAbsolutePath());
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Load default krb5.conf
+ * @return The AdminConfig
+ * @throws KrbException e
+ */
+ public static AdminConfig getDefaultConfig() throws KrbException {
+ File confFile = null;
+ File confDir;
+ String tmpEnv;
+
+ try {
+ Map<String, String> mapEnv = System.getenv();
+ tmpEnv = mapEnv.get(KRB5_ENV_NAME);
+ } catch (SecurityException e) {
+ tmpEnv = null;
+ }
+ if (tmpEnv != null) {
+ confFile = new File(tmpEnv);
+ if (!confFile.exists()) {
+ throw new KrbException("krb5 conf not found. Invalid env "
+ + KRB5_ENV_NAME);
+ }
+ } else {
+ confDir = new File("/etc/"); // for Linux. TODO: fix for Win etc.
+ if (confDir.exists()) {
+ confFile = new File(confDir, "krb5.conf");
+ }
+ }
+
+ AdminConfig adminConfig = new AdminConfig();
+ if (confFile != null && confFile.exists()) {
+ try {
+ adminConfig.addKrb5Config(confFile);
+ } catch (IOException e) {
+ throw new KrbException("Failed to load krb config "
+ + confFile.getAbsolutePath());
+ }
+ }
+
+ return adminConfig;
+ }
+
+ /**
+ * Get KDC network transport addresses according to krb client setting.
+ * @param setting The krb setting
+ * @return UDP and TCP addresses pair
+ * @throws KrbException e
+ */
+ public static TransportPair getTransportPair(
+ AdminSetting setting) throws KrbException {
+ TransportPair result = new TransportPair();
+
+ int tcpPort = setting.checkGetKdcTcpPort();
+ if (tcpPort > 0) {
+ result.tcpAddress = new InetSocketAddress(
+ setting.getKdcHost(), tcpPort);
+ }
+ int udpPort = setting.checkGetKdcUdpPort();
+ if (udpPort > 0) {
+ result.udpAddress = new InetSocketAddress(
+ setting.getKdcHost(), udpPort);
+ }
+
+ return result;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/RemoteKadminImpl.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/RemoteKadminImpl.java
new file mode 100644
index 0000000..c4ac154
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/RemoteKadminImpl.java
@@ -0,0 +1,207 @@
+/**
+ * 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.kadmin.remote;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.DefaultAdminHandler;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.InternalAdminClient;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.AddPrincipalRequest;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.AdminRequest;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.DeletePrincipalRequest;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.GetprincsRequest;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.RenamePrincipalRequest;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Server side admin facilities from remote, similar to MIT Kadmin remote mode.
+ * It uses GSSAPI and XDR to communicate with remote KDC/kadmind to do the
+ * requested operations. In the client side, it simply wraps and sends the
+ * request info to the admin kadmind side, and then unwraps the response for
+ * the operation result.
+ *
+ * TO BE IMPLEMENTED.
+ */
+public class RemoteKadminImpl implements Kadmin {
+
+ private InternalAdminClient innerClient;
+ private KrbTransport transport;
+
+ public RemoteKadminImpl(InternalAdminClient innerClient) throws KrbException {
+ this.innerClient = innerClient;
+ TransportPair tpair = null;
+ try {
+ tpair = AdminUtil.getTransportPair(innerClient.getSetting());
+ } catch (KrbException e) {
+ e.printStackTrace();
+ }
+ KrbNetwork network = new KrbNetwork();
+ network.setSocketTimeout(innerClient.getSetting().getTimeout());
+ try {
+ transport = network.connect(tpair);
+ } catch (IOException e) {
+ throw new KrbException("Failed to create transport", e);
+ }
+ }
+
+ public InternalAdminClient getInnerClient() {
+ return innerClient;
+ }
+
+
+ @Override
+ public String getKadminPrincipal() {
+ return KrbUtil.makeKadminPrincipal(innerClient.getSetting().getKdcRealm()).getName();
+ }
+
+ @Override
+ public void addPrincipal(String principal) throws KrbException {
+ //generate an admin request
+ AdminRequest adRequest = new AddPrincipalRequest(principal);
+ adRequest.setTransport(transport);
+ //handle it
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ adminHandler.handleRequest(adRequest);
+
+ }
+
+ @Override
+ public void addPrincipal(String principal,
+ KOptions kOptions) throws KrbException {
+ AdminRequest adRequest = new AddPrincipalRequest(principal, kOptions);
+ //wrap buffer problem
+ adRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ adminHandler.handleRequest(adRequest);
+ }
+
+ @Override
+ public void addPrincipal(String principal,
+ String password) throws KrbException {
+ AdminRequest addPrincipalRequest = new AddPrincipalRequest(principal, password);
+ addPrincipalRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ adminHandler.handleRequest(addPrincipalRequest);
+ }
+
+ @Override
+ public void addPrincipal(String principal, String password,
+ KOptions kOptions) throws KrbException {
+
+ }
+
+ @Override
+ public void exportKeytab(File keytabFile,
+ String principal) throws KrbException {
+
+ }
+
+ @Override
+ public void exportKeytab(File keytabFile,
+ List<String> principals) throws KrbException {
+
+ }
+
+ @Override
+ public void exportKeytab(File keytabFile) throws KrbException {
+
+ }
+
+ @Override
+ public void removeKeytabEntriesOf(File keytabFile,
+ String principal) throws KrbException {
+
+ }
+
+ @Override
+ public void removeKeytabEntriesOf(File keytabFile, String principal,
+ int kvno) throws KrbException {
+
+ }
+
+ @Override
+ public void removeOldKeytabEntriesOf(File keytabFile,
+ String principal) throws KrbException {
+
+ }
+
+ @Override
+ public void deletePrincipal(String principal) throws KrbException {
+ AdminRequest deletePrincipalRequest = new DeletePrincipalRequest(principal);
+ deletePrincipalRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ adminHandler.handleRequest(deletePrincipalRequest);
+ }
+
+ @Override
+ public void modifyPrincipal(String principal,
+ KOptions kOptions) throws KrbException {
+
+ }
+
+ @Override
+ public void renamePrincipal(String oldPrincipalName,
+ String newPrincipalName) throws KrbException {
+ AdminRequest renamePrincipalRequest = new RenamePrincipalRequest(oldPrincipalName, newPrincipalName);
+ renamePrincipalRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ adminHandler.handleRequest(renamePrincipalRequest);
+ }
+
+ @Override
+ public List<String> getPrincipals() throws KrbException {
+ AdminRequest grtPrincsRequest = new GetprincsRequest();
+ grtPrincsRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ return adminHandler.handleRequestForList(grtPrincsRequest);
+ }
+
+ @Override
+ public List<String> getPrincipals(String globString) throws KrbException {
+ AdminRequest grtPrincsRequest = new GetprincsRequest(globString);
+ grtPrincsRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ return adminHandler.handleRequestForList(grtPrincsRequest);
+ }
+
+ @Override
+ public void changePassword(String principal,
+ String newPassword) throws KrbException {
+
+ }
+
+ @Override
+ public void updateKeys(String principal) throws KrbException {
+
+ }
+
+ @Override
+ public void release() throws KrbException {
+
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteAddPrincipalCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteAddPrincipalCommand.java
new file mode 100644
index 0000000..d3d27a5
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteAddPrincipalCommand.java
@@ -0,0 +1,65 @@
+/**
+ * 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.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+
+/**
+ * Remote add principal command
+ */
+public class RemoteAddPrincipalCommand extends RemoteCommand {
+
+ public static final String USAGE = "Usage: add_principal [options] <principal-name>\n"
+ + "\toptions are:\n"
+ + "\t\t[-randkey|-nokey]\n"
+ + "\t\t[-pw password]"
+ + "\tExample:\n"
+ + "\t\tadd_principal -pw mypassword alice\n";
+
+ public RemoteAddPrincipalCommand(AdminClient adminClient) {
+ super(adminClient);
+ }
+
+ @Override
+ public void execute(String input) throws KrbException {
+ String[] items = input.split("\\s+");
+
+ if (items.length < 2) {
+ System.err.println(USAGE);
+ return;
+ }
+
+ String adminRealm = adminClient.getAdminConfig().getAdminRealm();
+ String clientPrincipal = items[items.length - 1] + "@" + adminRealm;
+
+ if (!items[1].startsWith("-")) {
+ adminClient.requestAddPrincipal(clientPrincipal);
+ } else if (items[1].startsWith("-nokey")) {
+ adminClient.requestAddPrincipal(clientPrincipal);
+ } else if (items[1].startsWith("-pw")) {
+ String password = items[2];
+ adminClient.requestAddPrincipal(clientPrincipal, password);
+ } else {
+ System.err.println("add_principal command format error.");
+ System.err.println(USAGE);
+ }
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteCommand.java
new file mode 100644
index 0000000..d5ffe0f
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteCommand.java
@@ -0,0 +1,41 @@
+/**
+ * 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.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+
+/**
+ * Abstract class of all remote kadmin commands
+ */
+public abstract class RemoteCommand {
+
+ AdminClient adminClient;
+
+ public RemoteCommand(AdminClient adminClient) {
+ this.adminClient = adminClient;
+ }
+
+ /**
+ * Execute the remote kadmin command
+ * @param input String includes commands
+ */
+ public abstract void execute(String input) throws KrbException;
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteDeletePrincipalCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteDeletePrincipalCommand.java
new file mode 100644
index 0000000..e6368bd
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteDeletePrincipalCommand.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.kerberos.kerb.admin.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+
+import java.io.Console;
+import java.util.Scanner;
+
+/**
+ * Remote delete principal command
+ */
+public class RemoteDeletePrincipalCommand extends RemoteCommand {
+
+ public static final String USAGE = "Usage: delete_principal <principal-name>\n"
+ + "\tExample:\n"
+ + "\t\tdelete_principal alice\n";
+
+ public RemoteDeletePrincipalCommand(AdminClient adminClient) {
+ super(adminClient);
+ }
+
+ @Override
+ public void execute(String input) throws KrbException {
+ String[] items = input.split("\\s+");
+ if (items.length < 2) {
+ System.err.println(USAGE);
+ return;
+ }
+
+ String principal = items[items.length - 1] + "@"
+ + adminClient.getAdminConfig().getAdminRealm();
+ String reply;
+ Console console = System.console();
+ String prompt = "Are you sure to delete the principal? (yes/no, YES/NO, y/n, Y/N) ";
+ if (console == null) {
+ System.out.println("Couldn't get Console instance, "
+ + "maybe you're running this from within an IDE. "
+ + "Use scanner to read password.");
+ Scanner scanner = new Scanner(System.in, "UTF-8");
+ reply = getReply(scanner, prompt);
+ } else {
+ reply = getReply(console, prompt);
+ }
+ if (reply.equals("yes") || reply.equals("YES") || reply.equals("y") || reply.equals("Y")) {
+ adminClient.requestDeletePrincipal(principal);
+ } else if (reply.equals("no") || reply.equals("NO") || reply.equals("n") || reply.equals("N")) {
+ System.out.println("Principal \"" + principal + "\" not deleted.");
+ } else {
+ System.err.println("Unknown request, fail to delete the principal.");
+ System.err.println(USAGE);
+ }
+ }
+
+ private String getReply(Scanner scanner, String prompt) {
+ System.out.println(prompt);
+ return scanner.nextLine().trim();
+ }
+
+ private String getReply(Console console, String prompt) {
+ console.printf(prompt);
+ String line = console.readLine();
+ return line;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetprincsCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetprincsCommand.java
new file mode 100644
index 0000000..2e15281
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetprincsCommand.java
@@ -0,0 +1,65 @@
+/**
+ * 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.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+import java.util.List;
+
+public class RemoteGetprincsCommand extends RemoteCommand {
+ private static final String USAGE = "Usage: list_principals [expression]\n"
+ + "\t'expression' is a shell-style glob expression that can contain the wild-card characters ?, *, and []."
+ + "\tExample:\n"
+ + "\t\tlist_principals [expression]\n";
+
+ public RemoteGetprincsCommand(AdminClient adminClient) {
+ super(adminClient);
+ }
+
+ @Override
+ public void execute(String input) throws KrbException {
+ String[] items = input.split("\\s+");
+ //String param = items[0];
+ if (items.length > 2) {
+ System.err.println(USAGE);
+ return;
+ }
+
+ List<String> principalLists = null;
+
+ if (items.length == 1) {
+ principalLists = adminClient.requestGetprincs();
+ } else {
+ //have expression
+ String exp = items[1];
+ principalLists = adminClient.requestGetprincsWithExp(exp);
+ }
+
+ if (principalLists.size() == 0 || principalLists.size() == 1 && principalLists.get(0).isEmpty()) {
+ return;
+ } else {
+ System.out.println("Principals are listed:");
+ for (int i = 0; i < principalLists.size(); i++) {
+ System.out.println(principalLists.get(i));
+ }
+ }
+ }
+
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemotePrintUsageCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemotePrintUsageCommand.java
new file mode 100644
index 0000000..a27e252
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemotePrintUsageCommand.java
@@ -0,0 +1,42 @@
+/**
+ * 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.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+public class RemotePrintUsageCommand extends RemoteCommand {
+
+ private static final String LISTPRINCSUSAGE = "Usage: list_principals [expression]\n"
+ + "\t'expression' is a shell-style glob expression that can contain "
+ + "the wild-card characters ?, *, and [].\n"
+ + "\tExample:\n"
+ + "\t\tlist_principals [expression]\n";
+
+ public RemotePrintUsageCommand() {
+ super(null);
+ }
+
+ @Override
+ public void execute(String input) throws KrbException {
+ if (input.startsWith("listprincs")) {
+ System.out.println(LISTPRINCSUSAGE);
+ }
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteRenamePrincipalCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteRenamePrincipalCommand.java
new file mode 100644
index 0000000..fd0cd61
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteRenamePrincipalCommand.java
@@ -0,0 +1,85 @@
+/**
+ * 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.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+
+import java.io.Console;
+import java.util.Scanner;
+
+/**
+ * Remote rename principal command
+ */
+public class RemoteRenamePrincipalCommand extends RemoteCommand {
+ public static final String USAGE = "Usage: rename_principal <old_principal_name>"
+ + " <new_principal_name>\n"
+ + "\tExample:\n"
+ + "\t\trename_principal alice bob\n";
+
+ public RemoteRenamePrincipalCommand(AdminClient adminClient) {
+ super(adminClient);
+ }
+
+ @Override
+ public void execute(String input) throws KrbException {
+ String[] items = input.split("\\s+");
+ if (items.length < 3) {
+ System.err.println(USAGE);
+ return;
+ }
+
+ String adminRealm = adminClient.getAdminConfig().getAdminRealm();
+ String oldPrincipalName = items[items.length - 2] + "@" + adminRealm;
+ String newPrincipalName = items[items.length - 1] + "@" + adminRealm;
+
+ String reply;
+ Console console = System.console();
+ String prompt = "Are you sure to rename the principal? (yes/no, YES/NO, y/n, Y/N) ";
+ if (console == null) {
+ System.out.println("Couldn't get Console instance, "
+ + "maybe you're running this from within an IDE. "
+ + "Use scanner to read password.");
+ Scanner scanner = new Scanner(System.in, "UTF-8");
+ reply = getReply(scanner, prompt);
+ } else {
+ reply = getReply(console, prompt);
+ }
+ if (reply.equals("yes") || reply.equals("YES") || reply.equals("y") || reply.equals("Y")) {
+ adminClient.requestRenamePrincipal(oldPrincipalName, newPrincipalName);
+ } else if (reply.equals("no") || reply.equals("NO") || reply.equals("n") || reply.equals("N")) {
+ System.out.println("Principal \"" + oldPrincipalName + "\" not renamed.");
+ } else {
+ System.err.println("Unknown request, fail to rename the principal.");
+ System.err.println(USAGE);
+ }
+ }
+
+ private String getReply(Scanner scanner, String prompt) {
+ System.out.println(prompt);
+ return scanner.nextLine().trim();
+ }
+
+ private String getReply(Console console, String prompt) {
+ console.printf(prompt);
+ String line = console.readLine();
+ return line;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/AbstractInternalAdminClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/AbstractInternalAdminClient.java
new file mode 100644
index 0000000..1f1635f
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/AbstractInternalAdminClient.java
@@ -0,0 +1,71 @@
+/**
+ * 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.kadmin.remote.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminContext;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminSetting;
+
+/**
+ * A krb client API for applications to interact with KDC
+ */
+public abstract class AbstractInternalAdminClient
+ implements InternalAdminClient {
+ private AdminContext context;
+ private final AdminSetting krbSetting;
+
+ public AbstractInternalAdminClient(AdminSetting krbSetting) {
+ this.krbSetting = krbSetting;
+ }
+
+ protected AdminContext getContext() {
+ return context;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public AdminSetting getSetting() {
+ return krbSetting;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init() throws KrbException {
+ context = new AdminContext();
+ context.init(krbSetting);
+ }
+
+ /**
+ * Fix principal name.
+ *
+ * @param principal The principal name
+ * @return The fixed principal
+ */
+ protected String fixPrincipal(String principal) {
+ if (!principal.contains("@")) {
+ principal += "@" + krbSetting.getKdcRealm();
+ }
+ return principal;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/DefaultAdminHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/DefaultAdminHandler.java
new file mode 100644
index 0000000..3d05b50
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/DefaultAdminHandler.java
@@ -0,0 +1,79 @@
+/**
+ * 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.kadmin.remote.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminHandler;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.AdminRequest;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class DefaultAdminHandler extends AdminHandler {
+
+ /**
+ * Use super.handleRequest to send message
+ * and use this to receive message.
+ */
+ @Override
+ public void handleRequest(AdminRequest adminRequest) throws KrbException {
+ /**super is used to send message*/
+ super.handleRequest(adminRequest);
+
+ KrbTransport transport = adminRequest.getTransport();
+ ByteBuffer receiveMessage = null;
+ try {
+ receiveMessage = transport.receiveMessage();
+ } catch (IOException e) {
+ throw new KrbException("Admin receives response message failed", e);
+ }
+ super.onResponseMessage(adminRequest, receiveMessage);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void sendMessage(AdminRequest adminRequest,
+ ByteBuffer requestMessage) throws IOException {
+ KrbTransport transport = adminRequest.getTransport();
+ transport.sendMessage(requestMessage);
+ }
+
+ @Override
+ public List<String> handleRequestForList(AdminRequest adminRequest) throws KrbException {
+ /**send message*/
+ super.handleRequest(adminRequest);
+
+ KrbTransport transport = adminRequest.getTransport();
+ ByteBuffer receiveMessage = null;
+ List<String> prinicalList = null;
+ try {
+ receiveMessage = transport.receiveMessage();
+ prinicalList = super.onResponseMessageForList(adminRequest, receiveMessage);
+ } catch (IOException e) {
+ throw new KrbException("Admin receives response message failed", e);
+ }
+
+ return prinicalList;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/DefaultInternalAdminClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/DefaultInternalAdminClient.java
new file mode 100644
index 0000000..2d40b6f
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/DefaultInternalAdminClient.java
@@ -0,0 +1,71 @@
+/**
+ * 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.kadmin.remote.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminHandler;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminSetting;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminUtil;
+import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.IOException;
+
+/**
+ * A default krb client implementation.
+ */
+public class DefaultInternalAdminClient extends AbstractInternalAdminClient {
+
+ private DefaultAdminHandler adminHandler;
+ private KrbTransport transport;
+
+ public DefaultInternalAdminClient(AdminSetting krbSetting) {
+ super(krbSetting);
+ }
+
+ public AdminHandler getAdminHanlder() {
+ return adminHandler;
+ }
+
+ public KrbTransport getTransport() {
+ return transport;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init() throws KrbException {
+ super.init();
+
+ this.adminHandler = new DefaultAdminHandler();
+ adminHandler.init(getContext());
+
+ TransportPair tpair = AdminUtil.getTransportPair(getSetting());
+ KrbNetwork network = new KrbNetwork();
+ network.setSocketTimeout(getSetting().getTimeout());
+ try {
+ transport = network.connect(tpair);
+ } catch (IOException e) {
+ throw new KrbException("Failed to create transport", e);
+ }
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/InternalAdminClient.java
similarity index 61%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/InternalAdminClient.java
index 325f1db..47bfd3d 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/impl/InternalAdminClient.java
@@ -17,8 +17,25 @@
* under the License.
*
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl;
-public class KadminTest {
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminSetting;
+/**
+ * An internal krb client interface.
+ */
+public interface InternalAdminClient {
+
+ /**
+ * Init with all the necessary options.
+ * @throws KrbException e
+ */
+ void init() throws KrbException;
+
+ /**
+ * Get krb client settings.
+ * @return setting
+ */
+ AdminSetting getSetting();
}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/AddPrincipalRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/AddPrincipalRequest.java
new file mode 100644
index 0000000..96622bc
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/AddPrincipalRequest.java
@@ -0,0 +1,114 @@
+/**
+ * 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.kadmin.remote.request;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.message.AddPrincipalReq;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessageCode;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminMessageType;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * AddPrincipal request
+ */
+public class AddPrincipalRequest extends AdminRequest {
+
+ private KOptions kOptions;
+ private String password;
+
+ public AddPrincipalRequest(String principal) {
+ super(principal);
+ }
+
+ public AddPrincipalRequest(String principal, KOptions kOptions) {
+ super(principal);
+ this.kOptions = kOptions;
+ }
+
+ public AddPrincipalRequest(String principal, String password) {
+ super(principal);
+ this.password = password;
+ }
+
+ public AddPrincipalRequest(String princial, KOptions kOptions, String password) {
+ super(princial);
+ this.kOptions = kOptions;
+ this.password = password;
+ }
+
+
+ @Override
+ public void process() throws KrbException {
+ super.process();
+ /**replace this with encode in handler*/
+ AddPrincipalReq addPrincipalReq = new AddPrincipalReq();
+ /** encode admin message:
+ * encode type
+ * encode paranum
+ * encode principal name
+ * (encode koptions)
+ * (encode passsword)
+ */
+ int paramNum = getParamNum();
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[paramNum + 2];
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.ADD_PRINCIPAL_REQ);
+ xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, paramNum);
+ xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, getPrincipal());
+ if (paramNum == 2 && kOptions != null) {
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRUCT, kOptions); /////koption
+ } else if (paramNum == 2 && password != null) {
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRING, password);
+ } else if (paramNum == 3) {
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRUCT, kOptions); ////koption
+ xdrFieldInfos[4] = new XdrFieldInfo(4, XdrDataType.STRING, password);
+ }
+ AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
+ byte[] encodeBytes;
+ try {
+ encodeBytes = value.encode();
+ } catch (IOException e) {
+ throw new KrbException("Xdr encode error when generate add principal request.", e);
+ }
+ ByteBuffer messageBuffer = ByteBuffer.wrap(encodeBytes);
+ addPrincipalReq.setMessageBuffer(messageBuffer);
+
+ setAdminReq(addPrincipalReq);
+ }
+
+ public int getParamNum() {
+ int paramNum = 0;
+ if (getPrincipal() == null) {
+ throw new RuntimeException("Principal name missing.");
+ }
+ if (kOptions == null && password == null) {
+ paramNum = 1;
+ } else if (kOptions == null || password == null) {
+ paramNum = 2;
+ } else {
+ paramNum = 3;
+ }
+ return paramNum;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/AdminRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/AdminRequest.java
new file mode 100644
index 0000000..7c8d152
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/AdminRequest.java
@@ -0,0 +1,63 @@
+/**
+ * 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.kadmin.remote.request;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.admin.message.AdminReq;
+
+public class AdminRequest {
+ private String principal;
+ private KrbTransport transport;
+ private AdminReq adminReq;
+
+ public AdminRequest(String principal) {
+ this.principal = principal;
+ }
+
+ public String getPrincipal() {
+ return principal;
+ }
+
+ public void setPrincipal(String principal) {
+ this.principal = principal;
+ }
+
+ public void setAdminReq(AdminReq adminReq) {
+ this.adminReq = adminReq;
+ }
+
+ public AdminReq getAdminReq() {
+ return adminReq;
+ }
+
+ public void process() throws KrbException {
+ //encoding and set adminReq
+ }
+
+
+ public void setTransport(KrbTransport transport) {
+ this.transport = transport;
+ }
+
+ public KrbTransport getTransport() {
+ return transport;
+ }
+}
\ No newline at end of file
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/DeletePrincipalRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/DeletePrincipalRequest.java
new file mode 100644
index 0000000..929f324
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/DeletePrincipalRequest.java
@@ -0,0 +1,70 @@
+/**
+ * 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.kadmin.remote.request;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+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.DeletePrincipalReq;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * DeletePrincipal request
+ */
+public class DeletePrincipalRequest extends AdminRequest {
+ /** Admin delete principal do not need password or koptions. */
+
+ public DeletePrincipalRequest(String principal) {
+ super(principal);
+ }
+
+ @Override
+ public void process() throws KrbException {
+ super.process();
+ DeletePrincipalReq deletePrincipalReq = new DeletePrincipalReq();
+ /** encode admin message:
+ * encode type
+ * encode paranum
+ * encode principal name
+ * (encode koptions)
+ * (encode passsword)
+ */
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[3];
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.DELETE_PRINCIPAL_REQ);
+ xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, 1);
+ xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, getPrincipal());
+
+ AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
+ byte[] encodeBytes;
+ try {
+ encodeBytes = value.encode();
+ } catch (IOException e) {
+ throw new KrbException("Xdr encode error when generate delete principal request.", e);
+ }
+ ByteBuffer messageBuffer = ByteBuffer.wrap(encodeBytes);
+ deletePrincipalReq.setMessageBuffer(messageBuffer);
+
+ setAdminReq(deletePrincipalReq);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/GetprincsRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/GetprincsRequest.java
new file mode 100644
index 0000000..2794010
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/GetprincsRequest.java
@@ -0,0 +1,70 @@
+/**
+ * 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.kadmin.remote.request;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+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.GetprincsReq;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * GetprincsRequest request.
+ */
+public class GetprincsRequest extends AdminRequest {
+ private String globString = null;
+
+ public GetprincsRequest() {
+ super(null);
+ }
+
+ public GetprincsRequest(String globString) {
+ super(null);
+ this.globString = globString;
+ }
+
+ @Override
+ public void process() throws KrbException {
+ //encoding and set adminReq
+
+ GetprincsReq getprincsReq = new GetprincsReq();
+
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[3];
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.GET_PRINCS_REQ);
+ xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, 2);
+ xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, globString);
+
+ AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
+ byte[] encodeBytes;
+ try {
+ encodeBytes = value.encode();
+ } catch (IOException e) {
+ throw new KrbException("Xdr encode error when generate get principals request.", e);
+ }
+ ByteBuffer messageBuffer = ByteBuffer.wrap(encodeBytes);
+ getprincsReq.setMessageBuffer(messageBuffer);
+
+ setAdminReq(getprincsReq);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/RenamePrincipalRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/RenamePrincipalRequest.java
new file mode 100644
index 0000000..a7cfcc2
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/RenamePrincipalRequest.java
@@ -0,0 +1,74 @@
+/**
+ * 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.kadmin.remote.request;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+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.RenamePrincipalReq;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * RenamePrincipal request.
+ */
+public class RenamePrincipalRequest extends AdminRequest {
+ String newPrincipalName;
+
+ public RenamePrincipalRequest(String oldPrincipalName, String newPrincipalName) {
+ super(oldPrincipalName);
+ this.newPrincipalName = newPrincipalName;
+ }
+
+ @Override
+ public void process() throws KrbException {
+ super.process();
+
+ RenamePrincipalReq renamePrincipalReq = new RenamePrincipalReq();
+
+ /** encode admin message:
+ * encode type
+ * encode paranum
+ * encode old principal name
+ * encode new principal name
+ */
+ int paramNum = 2;
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[paramNum + 2];
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.RENAME_PRINCIPAL_REQ);
+ xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, paramNum);
+ xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, getPrincipal());
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRING, newPrincipalName);
+
+ AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
+ byte[] encodeBytes;
+ try {
+ encodeBytes = value.encode();
+ } catch (IOException e) {
+ throw new KrbException("Xdr encode error when generate rename principal request.", e);
+ }
+ ByteBuffer messageBuffer = ByteBuffer.wrap(encodeBytes);
+ renamePrincipalReq.setMessageBuffer(messageBuffer);
+
+ setAdminReq(renamePrincipalReq);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AddPrincipalRep.java
similarity index 73%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AddPrincipalRep.java
index 325f1db..3c52ab0 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AddPrincipalRep.java
@@ -6,19 +6,25 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
+/**
+ * Add principal reply, to general admin message
+ */
+public class AddPrincipalRep extends AdminRep {
+ public AddPrincipalRep() {
+ super(AdminMessageType.ADD_PRINCIPAL_REP);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AddPrincipalReq.java
similarity index 73%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AddPrincipalReq.java
index 325f1db..0450a0e 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AddPrincipalReq.java
@@ -6,19 +6,25 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
+/**
+ * Add principal request, to general admin message
+ */
+public class AddPrincipalReq extends AdminReq {
+ public AddPrincipalReq() {
+ super(AdminMessageType.ADD_PRINCIPAL_REQ);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessage.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessage.java
new file mode 100644
index 0000000..ec21f91
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessage.java
@@ -0,0 +1,56 @@
+/**
+ * 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.message;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Deal with messages sent and received between Kadmin and Kadmin Server.
+ * (MSB) (LSB)
+ * +-------+-------+-------+-------+
+ * |msg_type |para_num |prin_name |...(koptions, password) |
+ * +-------+-------+-------+-------+
+ */
+public class AdminMessage {
+ private AdminMessageType adminMessageType;
+ private ByteBuffer messageBuffer;
+
+ public AdminMessage(AdminMessageType adminMessageType) {
+ this.adminMessageType = adminMessageType;
+ }
+
+ public AdminMessageType getAdminMessageType() {
+ return adminMessageType;
+ }
+
+ public void setMessageBuffer(ByteBuffer messageBuffer) {
+ this.messageBuffer = messageBuffer;
+ }
+
+ public ByteBuffer getMessageBuffer() {
+ return messageBuffer;
+ }
+
+ public int encodingLength() {
+ return messageBuffer.limit(); // no + 4 is the length of whole message
+ }
+
+
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageCode.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageCode.java
new file mode 100644
index 0000000..016d577
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageCode.java
@@ -0,0 +1,90 @@
+/**
+ * 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.message;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+import org.apache.kerby.xdr.type.AbstractXdrType;
+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;
+
+/**
+ * An extend XdrStructType to encode and decode AdminMessage.
+ */
+public class AdminMessageCode extends XdrStructType {
+ public AdminMessageCode() {
+ super(XdrDataType.STRUCT);
+ }
+
+ public AdminMessageCode(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 ENUM:
+ fields[i] = new AdminMessageEnum((AdminMessageType) fieldInfos[i].getValue());
+ break;
+ case STRING:
+ fields[i] = new XdrString((String) fieldInfos[i].getValue());
+ break;
+ default:
+ fields[i] = null;
+ }
+
+ }
+ }
+
+ @Override
+ protected XdrStructType fieldsToValues(AbstractXdrType[] fields) {
+ int paramNum = (int) fields[1].getValue();
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[paramNum + 2];
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, fields[0].getValue());
+ xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, fields[1].getValue());
+ xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, fields[2].getValue());
+ if (paramNum == 2 && fields[3].getValue() instanceof KOptions) {
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRUCT, fields[3].getValue()); /////koption
+ } else if (paramNum == 2 && fields[3].getValue() instanceof String) {
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRING, fields[3].getValue());
+ } else if (paramNum == 3) {
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.STRUCT, fields[3].getValue()); ////koption
+ xdrFieldInfos[4] = new XdrFieldInfo(4, XdrDataType.STRING, fields[4].getValue());
+ }
+ return new AdminMessageCode(xdrFieldInfos);
+ }
+
+ @Override
+ protected AbstractXdrType[] getAllFields() {
+ AbstractXdrType[] fields = new AbstractXdrType[5];
+ fields[0] = new AdminMessageEnum();
+ fields[1] = new XdrInteger();
+ fields[2] = new XdrString();
+ fields[3] = new XdrString(); //suppose it is string
+ fields[4] = null; // kOptions is not supported.
+ return fields;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageEnum.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageEnum.java
new file mode 100644
index 0000000..2ea60b8
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageEnum.java
@@ -0,0 +1,41 @@
+/**
+ * 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.message;
+
+import org.apache.kerby.xdr.EnumType;
+import org.apache.kerby.xdr.type.XdrEnumerated;
+
+/**
+ * An extend XdrEnumerate to encode and decode AdminMessageType.
+ */
+public class AdminMessageEnum extends XdrEnumerated<AdminMessageType> {
+ public AdminMessageEnum() {
+ super(null);
+ }
+
+ public AdminMessageEnum(AdminMessageType value) {
+ super(value);
+ }
+ @Override
+ protected EnumType[] getAllEnumValues() {
+ return AdminMessageType.values();
+ }
+
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageType.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageType.java
new file mode 100644
index 0000000..f44187e
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminMessageType.java
@@ -0,0 +1,73 @@
+/**
+ * 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.message;
+
+import org.apache.kerby.xdr.EnumType;
+
+/**
+ * Type of Admin Message:
+ * NONE(-1)
+ * ADD_PRINCIPAL_REQ(0) add principal request
+ * ADD_PRINCIPAL_REP(1) add principal reply
+ * DELETE_PRINCIPAL_REQ(2),
+ * DELETE_PRINCIPAL_REP(3);
+ * RENAME_PRINCIPAL_REQ(4),
+ * RENAME_PRINCIPAL_REP(5);
+ *
+ */
+
+public enum AdminMessageType implements EnumType {
+ NONE(-1),
+ ADD_PRINCIPAL_REQ(0),
+ ADD_PRINCIPAL_REP(1),
+ DELETE_PRINCIPAL_REQ(2),
+ DELETE_PRINCIPAL_REP(3),
+ RENAME_PRINCIPAL_REQ(4),
+ RENAME_PRINCIPAL_REP(5),
+ GET_PRINCS_REQ(6),
+ GET_PRINCS_REP(7);
+
+ private int value;
+
+ AdminMessageType(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public int getValue() {
+ return value;
+ }
+
+ @Override
+ public String getName() {
+ return name();
+ }
+
+ public static AdminMessageType findType(int value) {
+ if (value >= 0) {
+ for (EnumType e : values()) {
+ if (e.getValue() == value) {
+ return (AdminMessageType) e;
+ }
+ }
+ }
+ return NONE;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminRep.java
similarity index 69%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminRep.java
index 325f1db..a26cd6b 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminRep.java
@@ -6,19 +6,28 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
+/**
+ * Use to construct Admin message.
+ * Probably two kinds of reply.
+ * add principal -- AdRep
+ * change password? -- chRep
+ */
+public class AdminRep extends AdminMessage {
+ public AdminRep(AdminMessageType messageType) {
+ super(messageType);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminReq.java
similarity index 69%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminReq.java
index 325f1db..c69218f 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/AdminReq.java
@@ -6,19 +6,29 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
+
+/**
+ * Use to construct Admin message.
+ * Probably two kinds of request.
+ * add principal -- AdReq
+ * change password? -- chReq
+ */
+public class AdminReq extends AdminMessage {
+ public AdminReq(AdminMessageType messageType) {
+ super(messageType);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/DeletePrincipalRep.java
similarity index 72%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/DeletePrincipalRep.java
index 325f1db..35b1f6e 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/DeletePrincipalRep.java
@@ -6,19 +6,25 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
+/**
+ * Delete principal reply, to general admin message
+ */
+public class DeletePrincipalRep extends AdminRep {
+ public DeletePrincipalRep() {
+ super(AdminMessageType.DELETE_PRINCIPAL_REP);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/DeletePrincipalReq.java
similarity index 72%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/DeletePrincipalReq.java
index 325f1db..ad3b320 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/DeletePrincipalReq.java
@@ -6,19 +6,25 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
+/**
+ * Delete principal request, to general admin message
+ */
+public class DeletePrincipalReq extends AdminReq {
+ public DeletePrincipalReq() {
+ super(AdminMessageType.DELETE_PRINCIPAL_REQ);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetprincsRep.java
similarity index 78%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetprincsRep.java
index 325f1db..2a6364a 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetprincsRep.java
@@ -6,19 +6,21 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
-
+public class GetprincsRep extends AdminRep {
+ public GetprincsRep() {
+ super(AdminMessageType.GET_PRINCS_REP);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetprincsReq.java
similarity index 78%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetprincsReq.java
index 325f1db..75e819b 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetprincsReq.java
@@ -6,19 +6,21 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
-
+public class GetprincsReq extends AdminReq {
+ public GetprincsReq() {
+ super(AdminMessageType.GET_PRINCS_REQ);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/KadminCode.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/KadminCode.java
new file mode 100644
index 0000000..c5d6359
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/KadminCode.java
@@ -0,0 +1,63 @@
+/**
+ * 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.message;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * Used to decode messages between admin and admin server.
+ */
+public class KadminCode {
+ public static ByteBuffer encodeMessage(AdminMessage adminMessage) {
+ int length = adminMessage.encodingLength();
+ // 4 is the head to go through network
+ ByteBuffer buffer = ByteBuffer.allocate(length + 4);
+ buffer.putInt(length); // head in network
+ //buffer.putInt(adminMessage.getAdminMessageType().getValue());
+ // type has been encoded in the admin message
+ buffer.put(adminMessage.getMessageBuffer());
+ buffer.flip();
+ return buffer;
+ }
+
+ public static AdminMessage decodeMessage(ByteBuffer buffer) throws IOException {
+ //go through network, the total length has been removed.
+ int type = buffer.getInt();
+ System.out.println("type: " + type);
+ AdminMessageType adminMessageType = AdminMessageType.findType(type);
+ AdminMessage adminMessage = null;
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+ if (adminMessageType == AdminMessageType.ADD_PRINCIPAL_REQ) {
+ adminMessage = new AddPrincipalReq();
+ System.out.println("check if decoding right: "
+ + new String(ByteBuffer.wrap(bytes).array()));
+ } else if (adminMessageType == AdminMessageType.ADD_PRINCIPAL_REP) {
+ adminMessage = new AddPrincipalRep();
+ System.out.println("check if decoding right2: "
+ + new String(ByteBuffer.wrap(bytes).array()));
+ } else {
+ throw new IOException("Unknown Admin Message Type: " + type);
+ }
+
+ return adminMessage;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/RenamePrincipalRep.java
similarity index 72%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/RenamePrincipalRep.java
index 325f1db..5406190 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/RenamePrincipalRep.java
@@ -6,19 +6,24 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
-
+/**
+ * Rename principal reply, to general admin message
+ */
+public class RenamePrincipalRep extends AdminRep {
+ public RenamePrincipalRep() {
+ super(AdminMessageType.RENAME_PRINCIPAL_REP);
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/RenamePrincipalReq.java
similarity index 72%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/RenamePrincipalReq.java
index 325f1db..4bc8c1b 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/RenamePrincipalReq.java
@@ -6,19 +6,24 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.admin.message;
-public class KadminTest {
-
+/**
+ * Rename principal request, to general admin message
+ */
+public class RenamePrincipalReq extends AdminReq {
+ public RenamePrincipalReq() {
+ super(AdminMessageType.RENAME_PRINCIPAL_REQ);
+ }
}
diff --git a/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KdcNetwork.java b/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KdcNetwork.java
index 5323225..135eb6e 100644
--- a/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KdcNetwork.java
+++ b/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KdcNetwork.java
@@ -124,7 +124,6 @@
}
}
-
private void checkUdpMessage() throws IOException {
InetSocketAddress fromAddress = (InetSocketAddress) udpServer.receive(recvBuffer);
if (fromAddress != null) {
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcSetting.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcSetting.java
index 85f4da7..c53d5d6 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcSetting.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcSetting.java
@@ -26,7 +26,7 @@
/**
* KDC setting that combines startup options and kdc config.
*/
-public class KdcSetting {
+public class KdcSetting implements ServerSetting {
private final KOptions startupOptions;
private final KdcConfig kdcConfig;
private final BackendConfig backendConfig;
diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/ServerSetting.java
similarity index 62%
copy from kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
copy to kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/ServerSetting.java
index 325f1db..7044693 100644
--- a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/KadminTest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/ServerSetting.java
@@ -6,19 +6,30 @@
* 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.
- *
+ * under the License.
+ *
*/
-package org.apache.kerby.kerberos.kerb.admin;
+package org.apache.kerby.kerberos.kerb.server;
-public class KadminTest {
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+/**
+ * Super clsss of KdcSetting and AdminServer Setting.
+ * This class is used to solve the problem of member variable in
+ * LocalKadminImpl (KdcSetting or AdminServerSetting).
+ */
+public interface ServerSetting {
+ String getKdcRealm();
+
+ KdcConfig getKdcConfig();
+
+ BackendConfig getBackendConfig();
}
diff --git a/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/server/SimpleKdcServer.java b/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/server/SimpleKdcServer.java
index c342d8b..4de8e7f 100644
--- a/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/server/SimpleKdcServer.java
+++ b/kerby-kerb/kerb-simplekdc/src/main/java/org/apache/kerby/kerberos/kerb/server/SimpleKdcServer.java
@@ -20,8 +20,8 @@
package org.apache.kerby.kerberos.kerb.server;
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.client.Krb5Conf;
import org.apache.kerby.kerberos.kerb.client.KrbClient;
import org.apache.kerby.kerberos.kerb.client.KrbConfig;
diff --git a/kerby-kerb/pom.xml b/kerby-kerb/pom.xml
index 4b2537b..d9879d9 100644
--- a/kerby-kerb/pom.xml
+++ b/kerby-kerb/pom.xml
@@ -37,6 +37,7 @@
<module>kerb-kdc-test</module>
<module>integration-test</module>
<module>kerb-admin</module>
+ <module>kerb-admin-server</module>
<module>kerb-simplekdc</module>
<module>kerb-client-api-all</module>
<module>kerb-server-api-all</module>
diff --git a/kerby-tool/kdc-tool/pom.xml b/kerby-tool/kdc-tool/pom.xml
index 64edba2..dd4d62c 100644
--- a/kerby-tool/kdc-tool/pom.xml
+++ b/kerby-tool/kdc-tool/pom.xml
@@ -51,6 +51,12 @@
<artifactId>kerb-admin</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.kerby</groupId>
+ <artifactId>kerb-admin-server</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
</dependencies>
</project>
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
index 1c97204..add63a4 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
@@ -21,9 +21,9 @@
import org.apache.kerby.KOptions;
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.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+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.tool.kadmin.command.AddPrincipalCommand;
import org.apache.kerby.kerberos.tool.kadmin.command.ChangePasswordCommand;
import org.apache.kerby.kerberos.tool.kadmin.command.DeletePrincipalCommand;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java
index e2f33ff..9c64351 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java
@@ -21,7 +21,7 @@
import org.apache.kerby.KOptionType;
import org.apache.kerby.KOptions;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
import java.util.Scanner;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalCommand.java
index e2374bd..c9b36be 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalCommand.java
@@ -21,8 +21,8 @@
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
import java.io.Console;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java
index 32fe808..b1843e5 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java
@@ -21,8 +21,8 @@
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
public class AddPrincipalsCommand extends KadminCommand {
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ChangePasswordCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ChangePasswordCommand.java
index f3d2f45..b4bc4a0 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ChangePasswordCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ChangePasswordCommand.java
@@ -21,8 +21,8 @@
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
import java.io.Console;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/DeletePrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/DeletePrincipalCommand.java
index 8322b7b..0a2e146 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/DeletePrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/DeletePrincipalCommand.java
@@ -20,8 +20,8 @@
package org.apache.kerby.kerberos.tool.kadmin.command;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.Kadmin;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import java.io.Console;
import java.util.Scanner;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/GetPrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/GetPrincipalCommand.java
index 6c4501f..bc8024a 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/GetPrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/GetPrincipalCommand.java
@@ -20,7 +20,7 @@
package org.apache.kerby.kerberos.tool.kadmin.command;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KadminCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KadminCommand.java
index 53890e2..46f1087 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KadminCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KadminCommand.java
@@ -19,7 +19,7 @@
*/
package org.apache.kerby.kerberos.tool.kadmin.command;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
public abstract class KadminCommand {
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
index 65802f4..d96d5a0 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabAddCommand.java
@@ -20,7 +20,7 @@
package org.apache.kerby.kerberos.tool.kadmin.command;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import java.io.File;
import java.util.List;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabRemoveCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabRemoveCommand.java
index d1d9df4..82ab676 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabRemoveCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/KeytabRemoveCommand.java
@@ -21,8 +21,8 @@
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
import java.io.File;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ListPrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ListPrincipalCommand.java
index 71d909f..d236c65 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ListPrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ListPrincipalCommand.java
@@ -20,7 +20,7 @@
package org.apache.kerby.kerberos.tool.kadmin.command;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import java.util.List;
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java
index 4d0d16b..f3fe0fc 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java
@@ -22,8 +22,8 @@
import org.apache.kerby.KOptionType;
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
public class ModifyPrincipalCommand extends KadminCommand {
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/RenamePrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/RenamePrincipalCommand.java
index 80d6785..ca31199 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/RenamePrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/RenamePrincipalCommand.java
@@ -21,12 +21,11 @@
import org.apache.kerby.KOptions;
import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.admin.Kadmin;
-import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
-import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.Kadmin;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.KadminOption;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadmin;
import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
-
public class RenamePrincipalCommand extends KadminCommand {
private static final String USAGE = "Usage: rename_principal [-force] old_principal new_principal\n";
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kdcinit/KdcInitTool.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kdcinit/KdcInitTool.java
index 4cf4de8..faf1cb2 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kdcinit/KdcInitTool.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kdcinit/KdcInitTool.java
@@ -20,8 +20,10 @@
package org.apache.kerby.kerberos.tool.kdcinit;
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.admin.server.kadmin.AdminServer;
+import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerConfig;
import org.apache.kerby.util.OSUtil;
import java.io.File;
@@ -53,6 +55,19 @@
+ " has been exported to the specified file "
+ keytabFile.getAbsolutePath() + ", please safely keep it, "
+ "in order to use kadmin tool later");
+
+ // Export protocol keytab file for remote admin tool
+ AdminServer adminServer = new AdminServer(confDir);
+ AdminServerConfig adminServerConfig = adminServer.getAdminServerConfig();
+ String principal = adminServerConfig.getProtocol() + "/"
+ + adminServerConfig.getAdminHost() + "@" + adminServerConfig.getAdminRealm();
+ kadmin.addPrincipal(principal);
+ File protocolFile = new File("protocol.keytab");
+ kadmin.exportKeytab(protocolFile, principal);
+ System.out.println("The keytab for protocol principal "
+ + " has been exported to the specified file "
+ + protocolFile.getAbsolutePath() + ", please safely keep it, "
+ + "in order to use remote kadmin tool later");
} finally {
kadmin.release();
}