DIRKRB-751: Fix remote kadmin sasl negotiation (#54)
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 e5a4b08..6510cbf 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
@@ -41,6 +41,7 @@
import org.apache.kerby.xdr.XdrDataType;
import org.apache.kerby.xdr.XdrFieldInfo;
import org.apache.kerby.xdr.type.XdrStructType;
+import org.xnio.sasl.SaslWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -60,6 +61,7 @@
public class AdminServerHandler {
private static final Logger LOG = LoggerFactory.getLogger(AdminServerHandler.class);
private final AdminServerContext adminServerContext;
+ private SaslWrapper saslServerWrapper;
/**
* Constructor with admin server context.
@@ -71,6 +73,14 @@
LOG.info("Admin realm: " + this.adminServerContext.getAdminRealm());
}
+ public void setSaslServerWrapper(SaslWrapper saslServerWrapper) {
+ this.saslServerWrapper = saslServerWrapper;
+ }
+
+ public SaslWrapper getSaslServerWrapper() {
+ return saslServerWrapper;
+ }
+
/**
* Process the client request message.
*
@@ -206,7 +216,8 @@
}
private ByteBuffer handleGetprincsReq(LocalKadmin localKadmin, XdrFieldInfo[] fieldInfos) throws IOException {
- String globString = ((String) fieldInfos[2].getValue());
+ int paramNum = ((int) fieldInfos[1].getValue());
+ String globString = paramNum != 0 ? ((String) fieldInfos[2].getValue()) : null;
List<String> princsList = null;
try {
@@ -326,7 +337,7 @@
AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
adminMessage.setMessageBuffer(ByteBuffer.wrap(value.encode()));
- return KadminCode.encodeMessage(adminMessage);
+ return KadminCode.encodeWrapMessage(adminMessage, getSaslServerWrapper());
}
private ByteBuffer infoPackageTool(File keytabFile, String dealType) throws IOException {
@@ -343,7 +354,7 @@
KeytabMessageCode value = new KeytabMessageCode(xdrFieldInfos);
adminMessage.setMessageBuffer(ByteBuffer.wrap(value.encode()));
- return KadminCode.encodeMessage(adminMessage);
+ return KadminCode.encodeWrapMessage(adminMessage, getSaslServerWrapper());
}
private ByteBuffer infoPackageTool(KrbIdentity identity, String dealType) throws IOException {
@@ -370,7 +381,7 @@
IdentityInfoCode value = new IdentityInfoCode(xdrFieldInfos);
adminMessage.setMessageBuffer(ByteBuffer.wrap(value.encode()));
- return KadminCode.encodeMessage(adminMessage);
+ return KadminCode.encodeWrapMessage(adminMessage, getSaslServerWrapper());
}
private String listToString(List<String> list) {
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
index f625c37..7978501 100644
--- 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
@@ -119,4 +119,17 @@
return result;
}
+
+ /**
+ * Fix principal name.
+ *
+ * @param principal The principal name
+ * @return The fixed principal
+ */
+ public static String fixPrincipal(String principal, AdminServerSetting setting) {
+ if (!principal.contains("@")) {
+ principal += "@" + setting.getKdcRealm();
+ }
+ return principal;
+ }
}
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
index b8eb0a7..50eff7e 100644
--- 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
@@ -20,9 +20,16 @@
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.kadmin.remote.NegotiationStatus;
+import org.apache.kerby.kerberos.kerb.admin.message.KadminCode;
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.admin.server.kadmin.AdminServerUtil;
+import org.apache.kerby.kerberos.kerb.common.KrbUtil;
+import org.apache.kerby.kerberos.kerb.transport.KrbTcpTransport;
import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.xnio.sasl.SaslUtils;
+import org.xnio.sasl.SaslWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,20 +39,21 @@
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
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.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.Map;
public class DefaultAdminServerHandler extends AdminServerHandler implements Runnable {
private static Logger logger = LoggerFactory.getLogger(DefaultAdminServerHandler.class);
+ private static final String MECHANISM = "GSSAPI";
private final KrbTransport transport;
- private static boolean sasl = false;
private AdminServerContext adminServerContext;
public DefaultAdminServerHandler(AdminServerContext adminServerContext, KrbTransport transport) {
@@ -56,31 +64,30 @@
@Override
public void run() {
- while (true) {
+ try {
+ doSaslHandshake();
+ } catch (Exception e) {
+ logger.error("With exception when SASL negotiation." + e);
+ return;
+ }
+ do {
try {
- if (!sasl) {
- logger.info("Doing the sasl negotiation !!!");
- try {
- saslNegotiation();
- } catch (Exception e) {
- logger.error("With exception when sasl negotiation." + e);
- }
- } else {
- ByteBuffer message = transport.receiveMessage();
- if (message == null) {
- logger.debug("No valid request recved. Disconnect actively");
- transport.release();
- break;
- }
- handleMessage(message);
+ ByteBuffer message = transport.receiveMessage();
+ if (message == null) {
+ logger.debug("No valid request recved. Disconnect actively");
+ transport.release();
+ break;
}
+ // unwrap SASL message
+ ByteBuffer unwrapMessage = ByteBuffer.wrap(getSaslServerWrapper().unwrap(message));
+ handleMessage(unwrapMessage);
} catch (IOException e) {
transport.release();
logger.debug("Transport or decoding error occurred, "
+ "disconnecting abnormally", e);
break;
}
- }
+ } while (!((KrbTcpTransport) transport).isClosed());
}
protected void handleMessage(ByteBuffer message) {
@@ -95,80 +102,95 @@
}
}
- private void saslNegotiation() throws Exception {
-
+ private void doSaslHandshake() 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() {
+ String fixedPrincipal = AdminServerUtil.fixPrincipal(principal, adminServerContext.getAdminServerSetting());
+ String adminPrincipal = KrbUtil.makeKadminPrincipal(
+ adminServerContext.getAdminServerSetting().getKdcRealm()).getName();
+
+ Subject subject = AuthUtil.loginUsingKeytab(fixedPrincipal, keytabFile);
+ Subject.doAs(subject, (PrivilegedExceptionAction<Object>) () -> {
+ boolean success = false;
+ try {
+ ByteBuffer message;
try {
- ByteBuffer message = null;
- try {
- message = transport.receiveMessage();
- } catch (SocketTimeoutException e) {
- // ignore time out
- return null;
- }
-
- Map<String, Object> props = new HashMap<>();
- 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) {
- logger.info("sasl negotiation success!!!");
- sasl = true;
- break;
- }
- sendMessage(message, ss);
- if (!ss.isComplete()) {
- logger.info("Waiting receive message");
- message = transport.receiveMessage();
- }
- }
- } catch (Exception e) {
- logger.error("With exception when sasl negotiation. " + e);
+ message = transport.receiveMessage();
+ } catch (SocketTimeoutException ignore) {
+ // Ignore time out, wake up to see if should continue to run.
+ // When client create a new tpc transport, socket always timeout,
+ // because the first connection will not send message to the server.
+ // SASL handshake is not performed until the connection is established.
+ return null;
}
- return null;
- }
- });
+ Map<String, Object> props = new HashMap<>();
+ 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(adminPrincipal);
+ SaslServer saslServer = Sasl.createSaslServer(MECHANISM, protocol,
+ serverName, props, callbackHandler);
+
+ if (saslServer == null) {
+ throw new Exception("Unable to find server implementation for: GSSAPI");
+ }
+
+ setSaslServerWrapper(SaslWrapper.create(saslServer));
+
+ while (!saslServer.isComplete()) {
+ int scComplete = message.getInt();
+ if (scComplete == NegotiationStatus.SUCCESS.getValue()) {
+ logger.info("Sasl Client completed");
+ }
+
+ byte[] challenge = null;
+ try {
+ challenge = SaslUtils.evaluateResponse(saslServer, message);
+ } catch (SaslException e) {
+ throw new Exception("Sasl server evaluate challenge failed. " + e);
+ }
+
+ if (!saslServer.isComplete()) {
+ // Send message to client only when SASL server is not complete
+ sendMessage(challenge, saslServer);
+
+ logger.info("Waiting receive message");
+ message = transport.receiveMessage();
+ }
+ }
+ success = true;
+ } finally {
+ if (!success) {
+ transport.release();
+ }
+ }
+ 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);
- logger.info("Send message to admin client.");
+ private void sendMessage(byte[] challenge, SaslServer saslServer) throws IOException {
+ NegotiationStatus status = saslServer.isComplete()
+ ? NegotiationStatus.SUCCESS : NegotiationStatus.CONTINUE;
+ ByteBuffer buffer = KadminCode.encodeSaslMessage(challenge, status);
+ try {
+ transport.sendMessage(buffer);
+ logger.info("Send message to admin client.");
+ } catch (SaslException e) {
+ logger.error("Failed to send message to client. " + e.toString());
+ }
}
private static class SaslGssCallbackHandler implements CallbackHandler {
+ private final String adminPrincipal;
+
+ SaslGssCallbackHandler(String principal) {
+ this.adminPrincipal = principal;
+ }
+
@Override
public void handle(Callback[] callbacks) throws
UnsupportedCallbackException {
@@ -184,9 +206,10 @@
if (ac != null) {
String authid = ac.getAuthenticationID();
String authzid = ac.getAuthorizationID();
- if (authid.equals(authzid)) {
+ if (authid.equals(authzid) && authid.equals(adminPrincipal)) {
ac.setAuthorized(true);
} else {
+ logger.warn("Client try to login using principal " + authid);
ac.setAuthorized(false);
}
if (ac.isAuthorized()) {
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 1d53c70..1f85708 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
@@ -24,7 +24,6 @@
import org.apache.kerby.kerberos.kerb.admin.kadmin.local.LocalKadminImpl;
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.server.kadmin.AdminServer;
import org.apache.kerby.kerberos.kerb.admin.server.kadmin.AdminServerConfig;
import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
@@ -33,9 +32,6 @@
import org.apache.kerby.kerberos.kerb.server.KdcConfig;
import org.apache.kerby.kerberos.kerb.server.KdcServer;
import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
-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.kerberos.kerb.type.base.PrincipalName;
import org.apache.kerby.util.NetworkUtil;
import org.junit.AfterClass;
@@ -47,14 +43,8 @@
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
import java.io.File;
-import java.nio.ByteBuffer;
-import java.security.PrivilegedAction;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.stream.Collectors;
import static org.junit.Assert.assertTrue;
@@ -219,64 +209,7 @@
}
private void doSaslHandShake(AdminClient adminClient, AdminConfig config) throws Exception {
- TransportPair tpair = AdminUtil.getTransportPair(adminClient.getSetting());
- KrbNetwork network = new KrbNetwork();
- network.setSocketTimeout(adminClient.getSetting().getTimeout());
- KrbTransport transport = network.connect(tpair);
Subject subject = AuthUtil.loginUsingKeytab(ADMIN_PRINCIPAL, new File(config.getKeyTabFile()));
- Subject.doAs(subject, (PrivilegedAction<Object>) () -> {
- try {
- Map<String, String> props = new HashMap<>();
- props.put(Sasl.QOP, "auth-conf");
- props.put(Sasl.SERVER_AUTH, "true");
- SaslClient saslClient = null;
-
- String protocol = config.getProtocol();
- String serverName = config.getServerName();
- saslClient = Sasl.createSaslClient(new String[]{"GSSAPI"}, null,
- protocol, serverName, props, null);
- if (saslClient == null) {
- System.out.println("Unable to find client implementation for: GSSAPI");
- return null;
- }
- byte[] response;
- response = saslClient.hasInitialResponse()
- ? saslClient.evaluateChallenge(new byte[0]) : new byte[0];
-
- sendMessage(response, saslClient, transport);
-
- 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, transport);
-
- if (!saslClient.isComplete()) {
- message = transport.receiveMessage();
- }
- }
- } catch (Exception e) {
- LOG.warn(e.getMessage());
- }
- return null;
- });
- }
-
- private void sendMessage(byte[] challenge, SaslClient saslClient, KrbTransport transport) throws Exception {
- 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();
- transport.sendMessage(buffer);
+ adminClient.setSubject(subject);
}
}
diff --git a/kerby-kerb/kerb-admin/pom.xml b/kerby-kerb/kerb-admin/pom.xml
index 84b110f..f6810d9 100644
--- a/kerby-kerb/kerb-admin/pom.xml
+++ b/kerby-kerb/kerb-admin/pom.xml
@@ -52,5 +52,10 @@
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.jboss.xnio</groupId>
+ <artifactId>xnio-api</artifactId>
+ <version>${xnio-api.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
index 763a53f..dad1e74 100644
--- 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
@@ -35,7 +35,7 @@
public class AuthUtil {
- public static final boolean ENABLE_DEBUG = true;
+ public static final boolean ENABLE_DEBUG = false;
private static String getKrb5LoginModuleName() {
return System.getProperty("java.vendor").contains("IBM")
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 78cf4af..6dd2d2d 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
@@ -22,7 +22,6 @@
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.RemoteCommand;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteAddPrincipalCommand;
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.command.RemoteDeletePrincipalCommand;
@@ -34,9 +33,6 @@
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 org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
@@ -51,23 +47,14 @@
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;
/**
* Command use of remote admin
*/
public class RemoteAdminClientTool {
private static final Logger LOG = LoggerFactory.getLogger(RemoteAdminClientTool.class);
- private static final byte[] EMPTY = new byte[0];
- private static KrbTransport transport;
private static final String PROMPT = RemoteAdminClientTool.class.getSimpleName() + ".remote";
private static final String USAGE = (OSUtil.isWindows()
? "Usage: bin\\remote-admin-client.cmd" : "Usage: sh bin/remote-admin-client.sh")
@@ -140,21 +127,6 @@
adminClient.init();
System.out.println("admin init successful");
- TransportPair tpair = null;
- try {
- tpair = AdminUtil.getTransportPair(adminClient.getSetting());
- } catch (KrbException e) {
- LOG.error("Fail to get transport pair. " + e);
- }
- 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;
@@ -163,60 +135,11 @@
new File(adminConfig.getKeyTabFile()));
} catch (LoginException e) {
LOG.error("Fail to login using keytab. " + e);
+ return;
}
- Subject.doAs(subject, new PrivilegedAction<Object>() {
- @Override
- public Object run() {
- try {
- Map<String, String> props = new HashMap<>();
- 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) {
- LOG.error("Fail to create sasl client. " + e);
- }
- 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) {
- LOG.error("Sasl client evaluate challenge failed." + e);
- }
-
- 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) {
- LOG.error("Failed to run. " + e.toString());
- }
- return null;
- }
- });
+ // set login subject, used by SASL negotiation
+ adminClient.setSubject(subject);
System.out.println("enter \"command\" to see legal commands.");
@@ -246,25 +169,6 @@
}
}
- 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) {
- LOG.error("Failed to send Kerberos message. " + e.toString());
- }
- }
-
private static void execute(AdminClient adminClient, String input) throws KrbException {
input = input.trim();
if (input.startsWith("command")) {
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 1937c19..fa20b29 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
@@ -26,6 +26,7 @@
import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.impl.InternalAdminClient;
import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
+import javax.security.auth.Subject;
import java.io.File;
import java.util.List;
@@ -39,6 +40,7 @@
private final AdminSetting adminSetting;
private InternalAdminClient innerClient;
+ private Subject subject = null;
/**
* Default constructor.
@@ -171,53 +173,57 @@
return adminConfig;
}
+ public void setSubject(Subject subject) {
+ this.subject = subject;
+ }
+
public void requestAddPrincipal(String principal) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.addPrincipal(principal);
}
public void requestAddPrincipal(String principal, String password) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.addPrincipal(principal, password);
}
public void requestDeletePrincipal(String principal) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.deletePrincipal(principal);
}
public void requestRenamePrincipal(String oldPrincipal, String newPrincipal) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.renamePrincipal(oldPrincipal, newPrincipal);
}
public List<String> requestGetprincs() throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
return remote.getPrincipals();
}
public List<String> requestGetprincsWithExp(String exp) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
return remote.getPrincipals(exp);
}
public void requestExportKeytab(File keytabFile, String principal) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.exportKeytab(keytabFile, principal);
}
public void requestExportKeytab(File keytabFile, List<String> principals) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.exportKeytab(keytabFile, principals);
}
public void requestChangePassword(String principal, String newPassword) throws KrbException {
- Kadmin remote = new RemoteKadminImpl(innerClient);
+ Kadmin remote = new RemoteKadminImpl(innerClient, subject);
remote.changePassword(principal, newPassword);
}
public KrbIdentity requestGetPrincipal(String principal) throws KrbException {
- RemoteKadminImpl remote = new RemoteKadminImpl(innerClient);
+ RemoteKadminImpl remote = new RemoteKadminImpl(innerClient, subject);
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 37f7980..6640945 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
@@ -33,6 +33,7 @@
import org.apache.kerby.kerberos.kerb.type.base.EncryptionType;
import org.apache.kerby.xdr.XdrFieldInfo;
import org.apache.kerby.xdr.type.XdrStructType;
+import org.xnio.sasl.SaslWrapper;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -54,15 +55,16 @@
* Handle the kdc request.
*
* @param adminRequest The admin request
+ * @param sasl The SASL client wrapper
* @throws KrbException e
*/
- public void handleRequest(AdminRequest adminRequest) throws KrbException {
+ public void handleRequest(AdminRequest adminRequest, SaslWrapper sasl) throws KrbException {
adminRequest.process();
AdminReq adminReq = adminRequest.getAdminReq();
- ByteBuffer requestMessage = KadminCode.encodeMessage(adminReq);
- requestMessage.flip();
try {
+ ByteBuffer requestMessage = KadminCode.encodeWrapMessage(adminReq, sasl);
+ requestMessage.flip();
sendMessage(adminRequest, requestMessage);
} catch (IOException e) {
throw new KrbException("Admin sends request message failed", e);
@@ -240,9 +242,12 @@
protected abstract void sendMessage(AdminRequest adminRequest,
ByteBuffer requestMessage) throws IOException;
- protected abstract List<String> handleRequestForList(AdminRequest adminRequest) throws KrbException;
-
- protected abstract byte[] handleRequestForBytes(AdminRequest adminRequest) throws KrbException;
+ protected abstract List<String> handleRequestForList(AdminRequest adminRequest,
+ SaslWrapper sasl) throws KrbException;
- protected abstract KrbIdentity handleRequestForIdentity(AdminRequest adminRequest) throws KrbException;
+ protected abstract byte[] handleRequestForBytes(AdminRequest adminRequest,
+ SaslWrapper sasl) throws KrbException;
+
+ protected abstract KrbIdentity handleRequestForIdentity(AdminRequest adminRequest,
+ SaslWrapper sasl) throws KrbException;
}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/NegotiationStatus.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/NegotiationStatus.java
new file mode 100644
index 0000000..3eae226
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/remote/NegotiationStatus.java
@@ -0,0 +1,40 @@
+/**
+ * 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.xdr.EnumType;
+public enum NegotiationStatus implements EnumType {
+ SUCCESS(0),
+ CONTINUE(1),
+ ERROR(2);
+
+ private final int value;
+ NegotiationStatus(int value) {
+ this.value = value;
+ }
+ @Override
+ public int getValue() {
+ return value;
+ }
+ @Override
+ public String getName() {
+ return name();
+ }
+}
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 e12a913..66517df 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
@@ -33,6 +33,7 @@
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.admin.message.KadminCode;
import org.apache.kerby.kerberos.kerb.common.KrbUtil;
import org.apache.kerby.kerberos.kerb.keytab.Keytab;
import org.apache.kerby.kerberos.kerb.request.KrbIdentity;
@@ -40,14 +41,24 @@
import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
import org.apache.kerby.kerberos.kerb.transport.TransportPair;
import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
+import org.xnio.sasl.SaslUtils;
+import org.xnio.sasl.SaslWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.security.auth.Subject;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.PrivilegedExceptionAction;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Server side admin facilities from remote, similar to MIT Kadmin remote mode.
@@ -60,11 +71,17 @@
*/
public class RemoteKadminImpl implements Kadmin {
private static final Logger LOG = LoggerFactory.getLogger(RemoteKadminImpl.class);
+ private static final String MECHANISM = "GSSAPI";
+ private static final byte[] EMPTY_BYTES = new byte[0];
private InternalAdminClient innerClient;
private KrbTransport transport;
+ private SaslClient saslClient = null;
+ private SaslWrapper saslClientWrapper = null;
+ private final Subject subject;
- public RemoteKadminImpl(InternalAdminClient innerClient) throws KrbException {
+ public RemoteKadminImpl(InternalAdminClient innerClient, Subject subject) throws KrbException {
this.innerClient = innerClient;
+ this.subject = subject;
TransportPair tpair = null;
try {
tpair = AdminUtil.getTransportPair(innerClient.getSetting());
@@ -78,6 +95,11 @@
} catch (IOException e) {
throw new KrbException("Failed to create transport", e);
}
+ try {
+ doSaslHandshake();
+ } catch (Exception e) {
+ throw new KrbException("Failed to do SASL handshake. " + e);
+ }
}
public InternalAdminClient getInnerClient() {
@@ -97,7 +119,7 @@
adRequest.setTransport(transport);
//handle it
AdminHandler adminHandler = new DefaultAdminHandler();
- adminHandler.handleRequest(adRequest);
+ adminHandler.handleRequest(adRequest, saslClientWrapper);
}
@@ -108,7 +130,7 @@
//wrap buffer problem
adRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- adminHandler.handleRequest(adRequest);
+ adminHandler.handleRequest(adRequest, saslClientWrapper);
}
@Override
@@ -117,7 +139,7 @@
AdminRequest addPrincipalRequest = new AddPrincipalRequest(principal, password);
addPrincipalRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- adminHandler.handleRequest(addPrincipalRequest);
+ adminHandler.handleRequest(addPrincipalRequest, saslClientWrapper);
}
@Override
@@ -139,7 +161,7 @@
AdminRequest exportKeytabRequest = new ExportKeytabRequest(principalsStr);
exportKeytabRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- byte[] keytabFileBytes = adminHandler.handleRequestForBytes(exportKeytabRequest);
+ byte[] keytabFileBytes = adminHandler.handleRequestForBytes(exportKeytabRequest, saslClientWrapper);
Keytab keytab = AdminHelper.loadKeytab(new ByteArrayInputStream(keytabFileBytes));
Keytab outputKeytab = AdminHelper.createOrLoadKeytab(keytabFile);
@@ -179,7 +201,7 @@
AdminRequest deletePrincipalRequest = new DeletePrincipalRequest(principal);
deletePrincipalRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- adminHandler.handleRequest(deletePrincipalRequest);
+ adminHandler.handleRequest(deletePrincipalRequest, saslClientWrapper);
}
@Override
@@ -194,7 +216,7 @@
AdminRequest renamePrincipalRequest = new RenamePrincipalRequest(oldPrincipalName, newPrincipalName);
renamePrincipalRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- adminHandler.handleRequest(renamePrincipalRequest);
+ adminHandler.handleRequest(renamePrincipalRequest, saslClientWrapper);
}
@Override
@@ -202,7 +224,7 @@
AdminRequest getPrincsRequest = new GetprincsRequest();
getPrincsRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- return adminHandler.handleRequestForList(getPrincsRequest);
+ return adminHandler.handleRequestForList(getPrincsRequest, saslClientWrapper);
}
@Override
@@ -210,7 +232,7 @@
AdminRequest getPrincsRequest = new GetprincsRequest(globString);
getPrincsRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- return adminHandler.handleRequestForList(getPrincsRequest);
+ return adminHandler.handleRequestForList(getPrincsRequest, saslClientWrapper);
}
@Override
@@ -219,7 +241,7 @@
AdminRequest changePwdRequest = new ChangePasswordRequest(principal, newPassword);
changePwdRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- adminHandler.handleRequest(changePwdRequest);
+ adminHandler.handleRequest(changePwdRequest, saslClientWrapper);
}
@Override
@@ -236,7 +258,7 @@
AdminRequest getPrincipalRequest = new GetPrincipalRequest(principalName);
getPrincipalRequest.setTransport(transport);
AdminHandler adminHandler = new DefaultAdminHandler();
- return adminHandler.handleRequestForIdentity(getPrincipalRequest);
+ return adminHandler.handleRequestForIdentity(getPrincipalRequest, saslClientWrapper);
}
private String listToString(List<String> list) {
@@ -250,4 +272,64 @@
}
return result.toString();
}
+
+ private void doSaslHandshake() throws Exception {
+ Subject.doAs(subject, (PrivilegedExceptionAction<Object>) () -> {
+ boolean success = false;
+ try {
+ Map<String, String> saslProps = new HashMap<>();
+ saslProps.put(Sasl.QOP, "auth-conf");
+ saslProps.put(Sasl.SERVER_AUTH, "true");
+ try {
+ String protocol = innerClient.getSetting().getAdminConfig().getProtocol();
+ String serverName = innerClient.getSetting().getAdminConfig().getServerName();
+ saslClient = Sasl.createSaslClient(new String[]{MECHANISM}, null,
+ protocol, serverName, saslProps, null);
+ this.saslClientWrapper = SaslWrapper.create(saslClient);
+ } catch (SaslException e) {
+ throw new KrbException("Fail to create SASL client. " + e);
+ }
+ if (saslClient == null) {
+ throw new KrbException("Unable to find client implementation for: GSSAPI");
+ }
+ byte[] response;
+ try {
+ response = saslClient.hasInitialResponse()
+ ? saslClient.evaluateChallenge(EMPTY_BYTES) : EMPTY_BYTES;
+ } catch (SaslException e) {
+ throw new KrbException("Sasl client evaluate challenge failed." + e);
+ }
+ sendSaslMessage(response);
+ ByteBuffer message = transport.receiveMessage();
+
+ while (!saslClient.isComplete()) {
+ int ssComplete = message.getInt();
+ if (ssComplete == NegotiationStatus.SUCCESS.getValue()) {
+ LOG.info("Sasl Server completed");
+ }
+ sendSaslMessage(SaslUtils.evaluateChallenge(saslClient, message));
+ if (!saslClient.isComplete()) {
+ message = transport.receiveMessage();
+ }
+
+ }
+ success = true;
+ } finally {
+ if (!success) {
+ transport.release();
+ }
+ }
+ return null;
+ });
+ }
+ private void sendSaslMessage(byte[] response) {
+ NegotiationStatus status = saslClient.isComplete()
+ ? NegotiationStatus.SUCCESS : NegotiationStatus.CONTINUE;
+ ByteBuffer buffer = KadminCode.encodeSaslMessage(response, status);
+ try {
+ transport.sendMessage(buffer);
+ } catch (IOException e) {
+ LOG.error("Failed to send message to server. ", e);
+ }
+ }
}
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 03e3e93..45321d8 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
@@ -24,6 +24,7 @@
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 org.xnio.sasl.SaslWrapper;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -36,18 +37,18 @@
* and use this to receive message.
*/
@Override
- public void handleRequest(AdminRequest adminRequest) throws KrbException {
- /**super is used to send message*/
- super.handleRequest(adminRequest);
+ public void handleRequest(AdminRequest adminRequest, SaslWrapper sasl) throws KrbException {
+ // super is used to send message
+ super.handleRequest(adminRequest, sasl);
KrbTransport transport = adminRequest.getTransport();
- ByteBuffer receiveMessage = null;
try {
- receiveMessage = transport.receiveMessage();
+ ByteBuffer receiveMessage = transport.receiveMessage();
+ ByteBuffer unwrapMessage = ByteBuffer.wrap(sasl.unwrap(receiveMessage));
+ super.onResponseMessage(adminRequest, unwrapMessage);
} catch (IOException e) {
throw new KrbException("Admin receives response message failed", e);
}
- super.onResponseMessage(adminRequest, receiveMessage);
}
/**
@@ -61,16 +62,17 @@
}
@Override
- public List<String> handleRequestForList(AdminRequest adminRequest) throws KrbException {
- /**send message*/
- super.handleRequest(adminRequest);
+ public List<String> handleRequestForList(AdminRequest adminRequest,
+ SaslWrapper sasl) throws KrbException {
+ // send message
+ super.handleRequest(adminRequest, sasl);
KrbTransport transport = adminRequest.getTransport();
- ByteBuffer receiveMessage = null;
- List<String> prinicalList = null;
+ List<String> prinicalList;
try {
- receiveMessage = transport.receiveMessage();
- prinicalList = super.onResponseMessageForList(adminRequest, receiveMessage);
+ ByteBuffer receiveMessage = transport.receiveMessage();
+ ByteBuffer unwrapMessage = ByteBuffer.wrap(sasl.unwrap(receiveMessage));
+ prinicalList = super.onResponseMessageForList(adminRequest, unwrapMessage);
} catch (IOException e) {
throw new KrbException("Admin receives response message failed", e);
}
@@ -79,15 +81,16 @@
}
@Override
- protected byte[] handleRequestForBytes(AdminRequest adminRequest) throws KrbException {
- super.handleRequest(adminRequest);
+ protected byte[] handleRequestForBytes(AdminRequest adminRequest,
+ SaslWrapper sasl) throws KrbException {
+ super.handleRequest(adminRequest, sasl);
KrbTransport transport = adminRequest.getTransport();
- ByteBuffer receiveMessage = null;
byte[] keytabFileBytes;
try {
- receiveMessage = transport.receiveMessage();
- keytabFileBytes = super.onResponseMessageForBytesArray(adminRequest, receiveMessage);
+ ByteBuffer receiveMessage = transport.receiveMessage();
+ ByteBuffer unwrapMessage = ByteBuffer.wrap(sasl.unwrap(receiveMessage));
+ keytabFileBytes = super.onResponseMessageForBytesArray(adminRequest, unwrapMessage);
} catch (IOException e) {
throw new KrbException("Admin receives response message failed", e);
}
@@ -95,15 +98,16 @@
}
@Override
- protected KrbIdentity handleRequestForIdentity(AdminRequest adminRequest) throws KrbException {
- super.handleRequest(adminRequest);
+ protected KrbIdentity handleRequestForIdentity(AdminRequest adminRequest,
+ SaslWrapper sasl) throws KrbException {
+ super.handleRequest(adminRequest, sasl);
KrbTransport transport = adminRequest.getTransport();
- ByteBuffer receiveMessage = null;
KrbIdentity identity;
try {
- receiveMessage = transport.receiveMessage();
- identity = super.onResponseMessageForIdentity(adminRequest, receiveMessage);
+ ByteBuffer receiveMessage = transport.receiveMessage();
+ ByteBuffer unwrapMessage = ByteBuffer.wrap(sasl.unwrap(receiveMessage));
+ identity = super.onResponseMessageForIdentity(adminRequest, unwrapMessage);
} catch (IOException e) {
throw new KrbException("Admin receives response message failed", e);
}
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
index 2794010..9c082c8 100644
--- 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
@@ -52,7 +52,7 @@
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[1] = new XdrFieldInfo(1, XdrDataType.INTEGER, 1);
xdrFieldInfos[2] = new XdrFieldInfo(2, XdrDataType.STRING, globString);
AdminMessageCode value = new AdminMessageCode(xdrFieldInfos);
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
index c5d6359..84db194 100644
--- 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
@@ -19,6 +19,11 @@
*/
package org.apache.kerby.kerberos.kerb.admin.message;
+
+import org.apache.kerby.kerberos.kerb.admin.kadmin.remote.NegotiationStatus;
+import org.xnio.sasl.SaslWrapper;
+
+import javax.security.sasl.SaslException;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -37,6 +42,31 @@
buffer.flip();
return buffer;
}
+
+ public static ByteBuffer encodeSaslMessage(byte[] bytes, NegotiationStatus status) {
+ // NegotiationStatus occupies 4 bytes
+ int length = bytes.length + 4;
+ // 4 is the head to go through network
+ ByteBuffer buffer = ByteBuffer.allocate(length + 4);
+ buffer.putInt(length);
+ buffer.putInt(status.getValue());
+ buffer.put(bytes);
+ buffer.flip();
+ return buffer;
+ }
+
+ public static ByteBuffer encodeWrapMessage(AdminMessage adminMessage,
+ SaslWrapper sasl) throws SaslException {
+ // encode the data to be sent to the peer, in order to use SASL negotiated layer
+ byte[] wrapBytes = sasl.wrap(adminMessage.getMessageBuffer());
+ int length = wrapBytes.length;
+ // 4 is the head to go through network
+ ByteBuffer buffer = ByteBuffer.allocate(length + 4);
+ buffer.putInt(length); // head in network
+ buffer.put(wrapBytes);
+ buffer.flip();
+ return buffer;
+ }
public static AdminMessage decodeMessage(ByteBuffer buffer) throws IOException {
//go through network, the total length has been removed.
diff --git a/kerby-kerb/kerb-common/pom.xml b/kerby-kerb/kerb-common/pom.xml
index e4c4a19..d9de7c9 100644
--- a/kerby-kerb/kerb-common/pom.xml
+++ b/kerby-kerb/kerb-common/pom.xml
@@ -50,5 +50,10 @@
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jboss.xnio</groupId>
+ <artifactId>xnio-api</artifactId>
+ <version>${xnio-api.version}</version>
+ </dependency>
</dependencies>
</project>
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 b40fa04..2965e81 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
@@ -162,5 +162,11 @@
}
}
+ public boolean isStopped() {
+ synchronized (this) {
+ return isStopped;
+ }
+ }
+
protected abstract void onNewTransport(KrbTransport transport);
}
diff --git a/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KrbTcpTransport.java b/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KrbTcpTransport.java
index 50f8306..02cb877 100644
--- a/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KrbTcpTransport.java
+++ b/kerby-kerb/kerb-common/src/main/java/org/apache/kerby/kerberos/kerb/transport/KrbTcpTransport.java
@@ -81,4 +81,8 @@
// System.err.println(e); // NOOP
}
}
+
+ public boolean isClosed() {
+ return socket.isClosed();
+ }
}
diff --git a/pom.xml b/pom.xml
index 1a264d9..37e1dce 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,6 +79,7 @@
<ini4j.version>0.5.4</ini4j.version>
<targetJdk.version>1.8</targetJdk.version>
<zookeeper.version>3.4.14</zookeeper.version>
+ <xnio-api.version>3.6.5.Final</xnio-api.version>
</properties>
<prerequisites>