DIRKRB-750 (#53)
* DIRKRB-750: Add get_principal cmd for remote admin tool
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
index 34bc014..1ef4d7d 100644
--- 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
@@ -32,9 +32,10 @@
STRING (0X04),
ENUM (0x05),
OPAQUE (0x06),
- UNSIGNED_INTEGER (0x07),
- STRUCT (0x08),
- UNION (0x09);
+ UNSIGNED_INTEGER (0x07),
+ STRUCT (0x08),
+ UNION (0x09),
+ LONG (0x0A);
/** The dataType value */
private int value;
diff --git a/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrLong.java b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrLong.java
new file mode 100644
index 0000000..6d601bc
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/main/java/org/apache/kerby/xdr/type/XdrLong.java
@@ -0,0 +1,82 @@
+/**
+ * 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;
+
+/**
+ * From RFC 4506 :
+ *
+ * (MSB) (LSB)
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |byte 0 |byte 1 |byte 2 |byte 3 |byte 4 |byte 5 |byte 6 |byte 7 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * <----------------------------64 bits---------------------------->
+ * HYPER INTEGER
+ * UNSIGNED HYPER INTEGER
+ */
+public class XdrLong extends XdrSimple<Long> {
+ public XdrLong() {
+ this((Long) null);
+ }
+
+ public XdrLong(Long value) {
+ super(XdrDataType.LONG, value);
+ }
+
+ /**
+ * The length of a signed long is 8.
+ * @return Length of a signed long type.
+ */
+ @Override
+ protected int encodingBodyLength() throws IOException {
+ return 8;
+ }
+
+ /**
+ * Encode Long type to bytes.
+ * Cannot only use toByteArray() because of fixed 4 bytes length.
+ */
+ @Override
+ protected void toBytes() throws IOException {
+ long value = getValue().longValue();
+ ByteBuffer buffer = ByteBuffer.allocate(8);
+ buffer.putLong(value);
+ buffer.flip();
+ setBytes(buffer.array());
+ }
+
+ /**
+ * Decode bytes to Long value.
+ */
+ @Override
+ protected void toValue() {
+ if (getBytes().length != 8) {
+ byte[] longBytes = ByteBuffer.allocate(8).put(getBytes(), 0, 8).array();
+ /**reset bytes in case the enum type is in a struct or union*/
+ setBytes(longBytes);
+ }
+ ByteBuffer buffer = ByteBuffer.wrap(getBytes());
+ setValue(buffer.getLong());
+ }
+}
\ No newline at end of file
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
index b5f2a9a..9c7b8c9 100644
--- 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
@@ -129,6 +129,7 @@
case UNSIGNED_INTEGER:
case ENUM:
case STRING:
+ case LONG:
return true;
default:
return false;
diff --git a/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrLongTest.java b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrLongTest.java
new file mode 100644
index 0000000..6fa0499
--- /dev/null
+++ b/kerby-common/kerby-xdr/src/test/java/org/apache/kerby/xdr/XdrLongTest.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.XdrLong;
+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 XdrLongTest {
+ @Test
+ public void testEncoding() throws IOException {
+ testEncodingWith(0L, "0x00 00 00 00 00 00 00 00");
+ testEncodingWith(1L, "0x00 00 00 00 00 00 00 01");
+ testEncodingWith(2L, "0x00 00 00 00 00 00 00 02");
+ testEncodingWith(127L, "0x00 00 00 00 00 00 00 7F");
+ testEncodingWith(128L, "0x00 00 00 00 00 00 00 80");
+ testEncodingWith(-1L, "0xFF FF FF FF FF FF FF FF");
+ testEncodingWith(-127L, "0xFF FF FF FF FF FF FF 81");
+ testEncodingWith(-255L, "0xFF FF FF FF FF FF FF 01");
+ testEncodingWith(-32768L, "0xFF FF FF FF FF FF 80 00");
+ testEncodingWith(1234567890L, "0x00 00 00 00 49 96 02 D2");
+ testEncodingWith(9223372036854775807L, "0x7F FF FF FF FF FF FF FF");
+ testEncodingWith(-9223372036854775807L, "0x80 00 00 00 00 00 00 01");
+ testEncodingWith(-9223372036854775808L, "0x80 00 00 00 00 00 00 00");
+ }
+
+ private void testEncodingWith(long value, String expectedEncoding) throws IOException {
+ byte[] expected = HexUtil.hex2bytesFriendly(expectedEncoding);
+ XdrLong aValue = new XdrLong(value);
+
+ byte[] encodingBytes = aValue.encode();
+ assertThat(encodingBytes).isEqualTo(expected);
+ }
+
+
+ @Test
+ public void testDecoding() throws IOException {
+ testDecodingWith(0L, "0x00 00 00 00 00 00 00 00");
+ testDecodingWith(1L, "0x00 00 00 00 00 00 00 01");
+ testDecodingWith(2L, "0x00 00 00 00 00 00 00 02");
+ testDecodingWith(127L, "0x00 00 00 00 00 00 00 7F");
+ testDecodingWith(128L, "0x00 00 00 00 00 00 00 80");
+ testDecodingWith(-1L, "0xFF FF FF FF FF FF FF FF");
+ testDecodingWith(-127L, "0xFF FF FF FF FF FF FF 81");
+ testDecodingWith(-255L, "0xFF FF FF FF FF FF FF 01");
+ testDecodingWith(-32768L, "0xFF FF FF FF FF FF 80 00");
+ testDecodingWith(1234567890L, "0x00 00 00 00 49 96 02 D2");
+ testDecodingWith(9223372036854775807L, "0x7F FF FF FF FF FF FF FF");
+ testDecodingWith(-9223372036854775807L, "0x80 00 00 00 00 00 00 01");
+ testDecodingWith(-9223372036854775808L, "0x80 00 00 00 00 00 00 00");
+ }
+
+ private void testDecodingWith(long expectedValue, String content) throws IOException {
+ XdrLong decoded = new XdrLong();
+
+ decoded.decode(HexUtil.hex2bytesFriendly(content));
+ assertThat(decoded.getValue().longValue()).isEqualTo(expectedValue);
+ }
+}
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
index 5ffbbf4..e5a4b08 100644
--- 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
@@ -33,6 +33,11 @@
import org.apache.kerby.kerberos.kerb.admin.message.KeytabMessageCode;
import org.apache.kerby.kerberos.kerb.admin.message.ExportKeytabRep;
import org.apache.kerby.kerberos.kerb.admin.message.ChangePasswordRep;
+import org.apache.kerby.kerberos.kerb.admin.message.IdentityInfoCode;
+import org.apache.kerby.kerberos.kerb.admin.message.GetPrincipalRep;
+import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
import org.apache.kerby.xdr.XdrDataType;
import org.apache.kerby.xdr.XdrFieldInfo;
import org.apache.kerby.xdr.type.XdrStructType;
@@ -46,6 +51,8 @@
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
/**
* admin server handler to process client acmin requests.
@@ -108,6 +115,10 @@
System.out.println("message type: change password req");
responseMessage = handleChangePwdReq(localKadmin, fieldInfos);
break;
+ case GET_PRINCIPAL_REQ:
+ System.out.println("message type: get principal req");
+ responseMessage = handleGetPrincipalRep(localKadmin, fieldInfos);
+ break;
default:
throw new KrbException("AdminMessageType error, can not handle the type: " + type);
}
@@ -273,6 +284,21 @@
return responseMessage;
}
+ private ByteBuffer handleGetPrincipalRep(LocalKadmin localKadmin, XdrFieldInfo[] fieldInfos) throws IOException {
+ String principal = fixPrincipal((String) fieldInfos[2].getValue());
+
+ try {
+ KrbIdentity identity = localKadmin.getPrincipal(principal);
+
+ ByteBuffer responseMessage = infoPackageTool(identity, "getPrincipal");
+ return responseMessage;
+ } catch (KrbException e) {
+ String error = String.format("Failed to get principal %s. ", principal) + e.toString();
+ ByteBuffer responseError = infoPackageTool(error, "getPrincipal");
+ return responseError;
+ }
+ }
+
private ByteBuffer infoPackageTool(String message, String dealType) throws IOException {
AdminMessage adminMessage = null;
XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[3];
@@ -320,6 +346,33 @@
return KadminCode.encodeMessage(adminMessage);
}
+ private ByteBuffer infoPackageTool(KrbIdentity identity, String dealType) throws IOException {
+ AdminMessage adminMessage = null;
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[9];
+ if ("getPrincipal".equals(dealType)) {
+ adminMessage = new GetPrincipalRep();
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.GET_PRINCIPAL_REP);
+ }
+
+ Map<EncryptionType, EncryptionKey> key = identity.getKeys();
+ // Join key EncryptionType with comma delimiter
+ String keySet = key.keySet().stream().map(EncryptionType::getName).collect(Collectors.joining(","));
+
+ xdrFieldInfos[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, 7);
+ xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, identity.getPrincipalName());
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.LONG, identity.getExpireTime().getTime());
+ xdrFieldInfos[4] = new XdrFieldInfo(4, XdrDataType.LONG, identity.getCreatedTime().getTime());
+ xdrFieldInfos[5] = new XdrFieldInfo(5, XdrDataType.INTEGER, identity.getKdcFlags());
+ xdrFieldInfos[6] = new XdrFieldInfo(6, XdrDataType.INTEGER, identity.getKeyVersion());
+ xdrFieldInfos[7] = new XdrFieldInfo(7, XdrDataType.INTEGER, key.size());
+ xdrFieldInfos[8] = new XdrFieldInfo(8, XdrDataType.STRING, keySet.toString());
+
+ IdentityInfoCode value = new IdentityInfoCode(xdrFieldInfos);
+ adminMessage.setMessageBuffer(ByteBuffer.wrap(value.encode()));
+
+ return KadminCode.encodeMessage(adminMessage);
+ }
+
private String listToString(List<String> list) {
if (list.isEmpty()) {
return null;
diff --git a/kerby-kerb/kerb-admin-server/src/test/java/org/apache/kerby/kerberos/kerb/admin/server/RemoteKadminTest.java b/kerby-kerb/kerb-admin-server/src/test/java/org/apache/kerby/kerberos/kerb/admin/server/RemoteKadminTest.java
index 23670db..1d53c70 100644
--- a/kerby-kerb/kerb-admin-server/src/test/java/org/apache/kerby/kerberos/kerb/admin/server/RemoteKadminTest.java
+++ b/kerby-kerb/kerb-admin-server/src/test/java/org/apache/kerby/kerberos/kerb/admin/server/RemoteKadminTest.java
@@ -29,6 +29,7 @@
import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerConfig;
import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
import org.apache.kerby.kerberos.kerb.server.KdcConfig;
import org.apache.kerby.kerberos.kerb.server.KdcServer;
import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
@@ -58,6 +59,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertEquals;
public class RemoteKadminTest {
private static final Logger LOG = LoggerFactory.getLogger(RemoteKadminTest.class);
@@ -207,6 +209,14 @@
Assert.fail("Login using new password failed: " + e.toString());
}
}
+
+ @Test
+ public void remoteGetPrincipalTest() throws Exception {
+ AdminClient adminClient = buildKadminRemoteClient();
+ KrbIdentity identity = adminClient.requestGetPrincipal("kadmin/EXAMPLE.COM");
+ KrbIdentity expectIdentity = new KrbIdentity("kadmin/EXAMPLE.COM@EXAMPLE.COM");
+ assertEquals(identity, expectIdentity);
+ }
private void doSaslHandShake(AdminClient adminClient, AdminConfig config) throws Exception {
TransportPair tpair = AdminUtil.getTransportPair(adminClient.getSetting());
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
index 676ca60..78cf4af 100644
--- 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
@@ -27,9 +27,10 @@
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteAddPrincipalCommand;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteDeletePrincipalCommand;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteRenamePrincipalCommand;
-import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteGetprincsCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteListPrincsCommand;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteKeytabAddCommand;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteChangePasswordCommand;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteGetPrincipalCommand;
import org.apache.kerby.kerberos.kerb.common.KrbUtil;
import org.apache.kerby.kerberos.kerb.server.KdcConfig;
import org.apache.kerby.kerberos.kerb.server.KdcUtil;
@@ -90,7 +91,9 @@
+ "ktadd, xst\n"
+ " Add entry(s) to a keytab\n"
+ "change_password, cpw\n"
- + " Change password\n";
+ + " Change password\n"
+ + "get_principal, getprinc\n"
+ + " Get principal\n";
public static void main(String[] args) throws Exception {
AdminClient adminClient;
@@ -218,7 +221,7 @@
System.out.println("enter \"command\" to see legal commands.");
Completer completer = new StringsCompleter("add_principal", "delete_principal", "rename_principal",
- "list_principals", "ktadd", "change_password");
+ "list_principals", "ktadd", "change_password", "get_principal");
Terminal terminal = null;
try {
@@ -282,13 +285,16 @@
executor = new RemoteRenamePrincipalCommand(adminClient);
} else if (input.startsWith("list_principals")
|| input.startsWith("listprincs")) {
- executor = new RemoteGetprincsCommand(adminClient);
+ executor = new RemoteListPrincsCommand(adminClient);
} else if (input.startsWith("ktadd")
|| input.startsWith("xst")) {
executor = new RemoteKeytabAddCommand(adminClient);
} else if (input.startsWith("change_password")
|| input.startsWith("cpw")) {
executor = new RemoteChangePasswordCommand(adminClient);
+ } else if (input.startsWith("get_principal")
+ || input.startsWith("getprinc")) {
+ executor = new RemoteGetPrincipalCommand(adminClient);
} else {
System.out.println(LEGAL_COMMANDS);
return;
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
index 1415ef9..1937c19 100644
--- 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
@@ -24,6 +24,7 @@
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 org.apache.kerby.kerberos.kerb.request.KrbIdentity;
import java.io.File;
import java.util.List;
@@ -192,14 +193,12 @@
public List<String> requestGetprincs() throws KrbException {
Kadmin remote = new RemoteKadminImpl(innerClient);
- List<String> principalLists = remote.getPrincipals();
- return principalLists;
+ return remote.getPrincipals();
}
public List<String> requestGetprincsWithExp(String exp) throws KrbException {
Kadmin remote = new RemoteKadminImpl(innerClient);
- List<String> principalLists = remote.getPrincipals(exp);
- return principalLists;
+ return remote.getPrincipals(exp);
}
public void requestExportKeytab(File keytabFile, String principal) throws KrbException {
@@ -216,4 +215,9 @@
Kadmin remote = new RemoteKadminImpl(innerClient);
remote.changePassword(principal, newPassword);
}
+
+ public KrbIdentity requestGetPrincipal(String principal) throws KrbException {
+ RemoteKadminImpl remote = new RemoteKadminImpl(innerClient);
+ return remote.getPrincipal(principal);
+ }
}
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
index e412551..37f7980 100644
--- 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
@@ -26,6 +26,11 @@
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.KeytabMessageCode;
+import org.apache.kerby.kerberos.kerb.admin.message.IdentityInfoCode;
+import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.KerberosTime;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
import org.apache.kerby.xdr.XdrFieldInfo;
import org.apache.kerby.xdr.type.XdrStructType;
@@ -187,6 +192,44 @@
return keytabFileBytes;
}
+ public KrbIdentity onResponseMessageForIdentity(AdminRequest adminRequest,
+ ByteBuffer responseMessage) throws KrbException {
+ KrbIdentity identity = null;
+
+ IdentityInfoCode decoded = new IdentityInfoCode();
+ 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_PRINCIPAL_REP:
+ if (adminRequest.getAdminReq().getAdminMessageType() == AdminMessageType.GET_PRINCIPAL_REQ) {
+ identity = new KrbIdentity((String) fieldInfos[2].getValue());
+
+ identity.setExpireTime(new KerberosTime((long) fieldInfos[3].getValue()));
+ identity.setCreatedTime(new KerberosTime((long) fieldInfos[4].getValue()));
+ identity.setKdcFlags((int) fieldInfos[5].getValue());
+ identity.setKeyVersion((int) fieldInfos[6].getValue());
+ int keySize = (int) fieldInfos[7].getValue();
+ String[] keySet = ((String) fieldInfos[8].getValue()).split(",");
+ for (int i = 0; i < keySize; i++) {
+ EncryptionKey key = new EncryptionKey();
+ key.setKeyType(EncryptionType.fromName(keySet[i]));
+ identity.addKey(key);
+ }
+
+ }
+ break;
+ default:
+ throw new KrbException("Response message type error: " + type);
+ }
+ return identity;
+ }
+
/**
* Send message to kdc.
*
@@ -200,4 +243,6 @@
protected abstract List<String> handleRequestForList(AdminRequest adminRequest) throws KrbException;
protected abstract byte[] handleRequestForBytes(AdminRequest adminRequest) throws KrbException;
+
+ protected abstract KrbIdentity handleRequestForIdentity(AdminRequest adminRequest) throws KrbException;
}
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
index fba40bd..e12a913 100644
--- 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
@@ -32,8 +32,10 @@
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.RenamePrincipalRequest;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.GetprincsRequest;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.ChangePasswordRequest;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.request.GetPrincipalRequest;
import org.apache.kerby.kerberos.kerb.common.KrbUtil;
import org.apache.kerby.kerberos.kerb.keytab.Keytab;
+import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
import org.apache.kerby.kerberos.kerb.transport.TransportPair;
@@ -197,18 +199,18 @@
@Override
public List<String> getPrincipals() throws KrbException {
- AdminRequest grtPrincsRequest = new GetprincsRequest();
- grtPrincsRequest.setTransport(transport);
+ AdminRequest getPrincsRequest = new GetprincsRequest();
+ getPrincsRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- return adminHandler.handleRequestForList(grtPrincsRequest);
+ return adminHandler.handleRequestForList(getPrincsRequest);
}
@Override
public List<String> getPrincipals(String globString) throws KrbException {
- AdminRequest grtPrincsRequest = new GetprincsRequest(globString);
- grtPrincsRequest.setTransport(transport);
+ AdminRequest getPrincsRequest = new GetprincsRequest(globString);
+ getPrincsRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- return adminHandler.handleRequestForList(grtPrincsRequest);
+ return adminHandler.handleRequestForList(getPrincsRequest);
}
@Override
@@ -229,6 +231,13 @@
public void release() throws KrbException {
}
+
+ public KrbIdentity getPrincipal(String principalName) throws KrbException {
+ AdminRequest getPrincipalRequest = new GetPrincipalRequest(principalName);
+ getPrincipalRequest.setTransport(transport);
+ AdminHandler adminHandler = new DefaultAdminHandler();
+ return adminHandler.handleRequestForIdentity(getPrincipalRequest);
+ }
private String listToString(List<String> list) {
if (list.isEmpty()) {
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetPrincipalCommand.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetPrincipalCommand.java
new file mode 100644
index 0000000..d6f6c96
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetPrincipalCommand.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.kerberos.kerb.admin.kadmin.remote.command;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
+import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
+
+public class RemoteGetPrincipalCommand extends RemoteCommand {
+ private static final String USAGE = "Usage: getprinc principalName\n"
+ + "\tExample:\n"
+ + "\t\tgetprinc hello@TEST.COM\n";
+
+ public RemoteGetPrincipalCommand(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 clientPrincipalName = items[items.length - 1];
+ KrbIdentity identity = null;
+ try {
+ identity = adminClient.requestGetPrincipal(clientPrincipalName);
+ } catch (KrbException e) {
+ System.err.println("Failed to get principal: " + clientPrincipalName + ". " + e.toString());
+ }
+ if (identity == null) {
+ return;
+ } else {
+ System.out.println("Principal is listed:");
+ System.out.println(
+ "Principal: " + identity.getPrincipalName() + "\n"
+ + "Expiration date: " + identity.getExpireTime() + "\n"
+ + "Created time: " + identity.getCreatedTime() + "\n"
+ + "KDC flags: " + identity.getKdcFlags() + "\n"
+ + "Key version: " + identity.getKeyVersion() + "\n"
+ + "Number of keys: " + identity.getKeys().size()
+ );
+
+ for (EncryptionType keyType: identity.getKeys().keySet()) {
+ System.out.println("key: " + keyType);
+ }
+ }
+ }
+}
\ No newline at end of file
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/RemoteListPrincsCommand.java
similarity index 94%
rename from kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteGetprincsCommand.java
rename to kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/command/RemoteListPrincsCommand.java
index 2e15281..b808c91 100644
--- 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/RemoteListPrincsCommand.java
@@ -23,13 +23,13 @@
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.AdminClient;
import java.util.List;
-public class RemoteGetprincsCommand extends RemoteCommand {
+public class RemoteListPrincsCommand 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) {
+ public RemoteListPrincsCommand(AdminClient adminClient) {
super(adminClient);
}
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
index 41615a7..03e3e93 100644
--- 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
@@ -22,6 +22,7 @@
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.request.KrbIdentity;
import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
import java.io.IOException;
@@ -92,4 +93,20 @@
}
return keytabFileBytes;
}
+
+ @Override
+ protected KrbIdentity handleRequestForIdentity(AdminRequest adminRequest) throws KrbException {
+ super.handleRequest(adminRequest);
+
+ KrbTransport transport = adminRequest.getTransport();
+ ByteBuffer receiveMessage = null;
+ KrbIdentity identity;
+ try {
+ receiveMessage = transport.receiveMessage();
+ identity = super.onResponseMessageForIdentity(adminRequest, receiveMessage);
+ } catch (IOException e) {
+ throw new KrbException("Admin receives response message failed", e);
+ }
+ return identity;
+ }
}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/GetPrincipalRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/GetPrincipalRequest.java
new file mode 100644
index 0000000..0413a22
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/request/GetPrincipalRequest.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.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.GetPrincipalReq;
+import org.apache.kerby.xdr.XdrDataType;
+import org.apache.kerby.xdr.XdrFieldInfo;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class GetPrincipalRequest extends AdminRequest {
+
+ public GetPrincipalRequest(String principal) {
+ super(principal);
+ }
+
+ @Override
+ public void process() throws KrbException {
+ super.process();
+
+ GetPrincipalReq getPrincipalReq = new GetPrincipalReq();
+ XdrFieldInfo[] xdrFieldInfos = new XdrFieldInfo[3];
+ xdrFieldInfos[0] = new XdrFieldInfo(0, XdrDataType.ENUM, AdminMessageType.GET_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 get principal request.", e);
+ }
+ ByteBuffer messageBuffer = ByteBuffer.wrap(encodeBytes);
+ getPrincipalReq.setMessageBuffer(messageBuffer);
+
+ setAdminReq(getPrincipalReq);
+ }
+}
\ No newline at end of file
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
index 7996355..d36c64c 100644
--- 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
@@ -46,7 +46,9 @@
EXPORT_KEYTAB_REQ(8),
EXPORT_KEYTAB_REP(9),
CHANGE_PWD_REQ(10),
- CHANGE_PWD_REP(11);
+ CHANGE_PWD_REP(11),
+ GET_PRINCIPAL_REQ(12),
+ GET_PRINCIPAL_REP(13);
private int value;
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetPrincipalRep.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetPrincipalRep.java
new file mode 100644
index 0000000..fbe0bea
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetPrincipalRep.java
@@ -0,0 +1,26 @@
+/**
+ * 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;
+
+public class GetPrincipalRep extends AdminRep {
+ public GetPrincipalRep() {
+ super(AdminMessageType.GET_PRINCIPAL_REP);
+ }
+}
\ No newline at end of file
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetPrincipalReq.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetPrincipalReq.java
new file mode 100644
index 0000000..d21ebd3
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/GetPrincipalReq.java
@@ -0,0 +1,26 @@
+/**
+ * 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;
+
+public class GetPrincipalReq extends AdminReq {
+ public GetPrincipalReq() {
+ super(AdminMessageType.GET_PRINCIPAL_REQ);
+ }
+}
\ No newline at end of file
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/IdentityInfoCode.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/IdentityInfoCode.java
new file mode 100644
index 0000000..2dc5001
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/message/IdentityInfoCode.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.message;
+
+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.XdrLong;
+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 IdentityInfo.
+ * fields[0]: reply message type
+ * fields[1]: message size except the first two elements
+ * fields[2]: identity principal name
+ * fields[3]: identity expire time
+ * fields[4]: identity created time
+ * fields[5]: identity kdc flags
+ * fields[6]: identity key version
+ * fields[7]: the size of identity encryption keys
+ * fields[8]: identity encryption type joined with coma delimiter
+ */
+public class IdentityInfoCode extends XdrStructType {
+ public IdentityInfoCode() {
+ super(XdrDataType.STRUCT);
+ }
+
+ public IdentityInfoCode(XdrFieldInfo[] fieldInfos) {
+ super(XdrDataType.STRUCT, fieldInfos);
+ }
+
+ @Override
+ protected void getStructTypeInstance(XdrType[] fields, 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;
+ case LONG:
+ fields[i] = new XdrLong((Long) 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());
+ xdrFieldInfos[3] = new XdrFieldInfo(3, XdrDataType.LONG, fields[3].getValue());
+ xdrFieldInfos[4] = new XdrFieldInfo(4, XdrDataType.LONG, fields[4].getValue());
+ xdrFieldInfos[5] = new XdrFieldInfo(5, XdrDataType.INTEGER, fields[5].getValue());
+ xdrFieldInfos[6] = new XdrFieldInfo(6, XdrDataType.INTEGER, fields[6].getValue());
+ xdrFieldInfos[7] = new XdrFieldInfo(7, XdrDataType.INTEGER, fields[7].getValue());
+ xdrFieldInfos[8] = new XdrFieldInfo(8, XdrDataType.STRING, fields[8].getValue());
+
+ return new IdentityInfoCode(xdrFieldInfos);
+ }
+
+ @Override
+ protected AbstractXdrType[] getAllFields() {
+ AbstractXdrType[] fields = new AbstractXdrType[9];
+ fields[0] = new AdminMessageEnum();
+ fields[1] = new XdrInteger();
+ fields[2] = new XdrString();
+ fields[3] = new XdrLong();
+ fields[4] = new XdrLong();
+ fields[5] = new XdrInteger();
+ fields[6] = new XdrInteger();
+ fields[7] = new XdrInteger();
+ fields[8] = new XdrString();
+ return fields;
+ }
+}
\ No newline at end of file