Merge remote-tracking branch 'asf/trunk' into kpasswd
diff --git a/kerb-admin-server/pom.xml b/kerb-admin-server/pom.xml
new file mode 100644
index 0000000..546f6da
--- /dev/null
+++ b/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/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/PasswdServerInit.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/PasswdServerInit.java
new file mode 100644
index 0000000..a80f253
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/PasswdServerInit.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.server;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServer;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerConfig;
+import org.apache.kerby.util.OSUtil;
+
+import java.io.File;
+
+/**
+ * A running tool for password server.
+ * Allow both tcp and udp.
+ * tcp port: 464
+ * udp port: 464
+ */
+public class PasswdServerInit {
+ private static final String USAGE = (OSUtil.isWindows()
+ ? "Usage: bin\\kpasswdServer.cmd" : "Usage: sh bin/kpasswdServer.sh")
+ + " <conf-file>\n"
+ + "\tExample:\n"
+ + "\t\t"
+ + (OSUtil.isWindows()
+ ? "bin\\kpasswdServer.cmd" : "sh bin/kpasswdServer.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];
+ PasswdServer passwdServer = new PasswdServer(new File(confDirPath));
+ PasswdServerConfig passwdServerConfig = passwdServer.getPasswdServerConfig();
+
+ passwdServer.setPasswdHost(passwdServerConfig.getPasswdHost());
+ passwdServer.setAllowTcp(true);
+ passwdServer.setAllowUdp(true); /**change password protocol allow both tcp and udp*/
+ passwdServer.setPasswdServerPort(passwdServerConfig.getPasswdPort());
+
+ try {
+ passwdServer.init();
+ } catch (KrbException e) {
+ System.err.println("Errors occurred when start admin server: " + e.getMessage());
+ System.exit(2);
+ }
+ passwdServer.start();
+ System.out.println("Password server started!");
+ }
+}
+
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServer.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServer.java
new file mode 100644
index 0000000..f473c1d
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServer.java
@@ -0,0 +1,268 @@
+/**
+ * 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.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.impl.DefaultInternalPasswdServerImpl;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.impl.InternalPasswdServer;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+
+import java.io.File;
+
+/**
+ * The implemented Kerberos passwd passwd API.
+ */
+public class PasswdServer {
+ private final PasswdServerConfig passwdServerConfig;
+ private final BackendConfig backendConfig;
+ private final PasswdServerSetting passwdServerSetting;
+ private final KOptions startupOptions;
+
+ private InternalPasswdServer innerPasswdServer;
+
+ /**
+ * Constructor passing both passwdConfig and backendConfig.
+ * @param passwdConfig The passwd config
+ * @param backendConfig The backend config
+ * @throws KrbException e
+ */
+ public PasswdServer(PasswdServerConfig passwdConfig,
+ BackendConfig backendConfig) throws KrbException {
+ this.passwdServerConfig = passwdConfig;
+ this.backendConfig = backendConfig;
+ startupOptions = new KOptions();
+ passwdServerSetting = new PasswdServerSetting(startupOptions,
+ passwdConfig, backendConfig);
+ }
+
+ /**
+ * Constructor given confDir where 'passwd.conf' and 'backend.conf' should be
+ * available.
+ * passwd.conf, that contains passwd passwd related items.
+ * backend.conf, that contains identity backend related items.
+ *
+ * @param confDir The conf dir
+ * @throws KrbException e
+ */
+ public PasswdServer(File confDir) throws KrbException {
+ PasswdServerConfig tmpPasswdServerConfig =
+ PasswdServerUtil.getPasswdServerConfig(confDir);
+ if (tmpPasswdServerConfig == null) {
+ tmpPasswdServerConfig = new PasswdServerConfig();
+ }
+ this.passwdServerConfig = tmpPasswdServerConfig;
+
+ BackendConfig tmpBackendConfig = PasswdServerUtil.getBackendConfig(confDir);
+ if (tmpBackendConfig == null) {
+ tmpBackendConfig = new BackendConfig();
+ }
+ tmpBackendConfig.setConfDir(confDir);
+ this.backendConfig = tmpBackendConfig;
+
+ startupOptions = new KOptions();
+ passwdServerSetting = new PasswdServerSetting(startupOptions,
+ passwdServerConfig, backendConfig);
+ }
+
+ /**
+ * Default constructor.
+ */
+ public PasswdServer() {
+ passwdServerConfig = new PasswdServerConfig();
+ backendConfig = new BackendConfig();
+ startupOptions = new KOptions();
+ passwdServerSetting = new PasswdServerSetting(startupOptions,
+ passwdServerConfig, backendConfig);
+ }
+
+ /**
+ * Set Passwd realm for ticket request
+ * @param realm The passwd realm
+ */
+ public void setPasswdServerRealm(String realm) {
+ startupOptions.add(PasswdServerOption.ADMIN_REALM, realm);
+ }
+
+ /**
+ * Set Passwd host.
+ * @param passwdHost The passwd host
+ */
+ public void setPasswdHost(String passwdHost) {
+ startupOptions.add(
+ PasswdServerOption.ADMIN_HOST,
+ passwdHost);
+ }
+
+ /**
+ * Set Passwd port.
+ * @param passwdPort The passwd port
+ */
+ public void setPasswdServerPort(int passwdPort) {
+ startupOptions.add(
+ PasswdServerOption.ADMIN_PORT,
+ passwdPort);
+ }
+
+ /**
+ * Set Passwd tcp port.
+ * @param passwdTcpPort The passwd tcp port
+ */
+ public void setPasswdTcpPort(int passwdTcpPort) {
+ startupOptions.add(
+ PasswdServerOption.ADMIN_TCP_PORT,
+ passwdTcpPort);
+ }
+
+ /**
+ * Set to allow UDP or not.
+ * @param allowUdp true if allow udp
+ */
+ public void setAllowUdp(boolean allowUdp) {
+ startupOptions.add(
+ PasswdServerOption.ALLOW_UDP,
+ allowUdp);
+ }
+
+ /**
+ * Set to allow TCP or not.
+ * @param allowTcp true if allow tcp
+ */
+ public void setAllowTcp(boolean allowTcp) {
+ startupOptions.add(
+ PasswdServerOption.ALLOW_TCP,
+ allowTcp);
+ }
+ /**
+ * Set Passwd udp port. Only makes sense when allowUdp is set.
+ * @param passwdUdpPort The passwd udp port
+ */
+ public void setPasswdUdpPort(int passwdUdpPort) {
+ startupOptions.add(
+ PasswdServerOption.ADMIN_UDP_PORT,
+ passwdUdpPort);
+ }
+
+ /**
+ * Set runtime folder.
+ * @param workDir The work dir
+ */
+ public void setWorkDir(File workDir) {
+ startupOptions.add(
+ PasswdServerOption.WORK_DIR,
+ workDir);
+ }
+
+ /**
+ * Allow to debug so have more logs.
+ */
+ public void enableDebug() {
+ startupOptions.add(
+ PasswdServerOption.ENABLE_DEBUG);
+ }
+
+ /**
+ * Allow to hook customized passwd implementation.
+ *
+ * @param innerPasswdServerImpl The inner passwd implementation
+ */
+ public void setInnerPasswdServerImpl(InternalPasswdServer innerPasswdServerImpl) {
+ startupOptions.add(
+ PasswdServerOption.INNER_ADMIN_IMPL,
+ innerPasswdServerImpl);
+ }
+
+ /**
+ * Get Passwd setting from startup options and configs.
+ * @return setting
+ */
+ public PasswdServerSetting getPasswdServerSetting() {
+ return passwdServerSetting;
+ }
+
+ /**
+ * Get the Passwd config.
+ * @return PasswdServerConfig
+ */
+ public PasswdServerConfig getPasswdServerConfig() {
+ return passwdServerConfig;
+ }
+
+ /**
+ * Get backend config.
+ *
+ * @return backend configuration
+ */
+ public BackendConfig getBackendConfig() {
+ return backendConfig;
+ }
+
+ /**
+ * Get identity service.
+ * @return IdentityService
+ */
+ public IdentityBackend getIdentityService() {
+ if (innerPasswdServer == null) {
+ throw new RuntimeException("Not init yet");
+ }
+ return innerPasswdServer.getIdentityBackend();
+ }
+
+ /**
+ * Initialize.
+ *
+ * @throws KrbException e.
+ */
+ public void init() throws KrbException {
+ if (startupOptions.contains(PasswdServerOption.INNER_ADMIN_IMPL)) {
+ innerPasswdServer = (InternalPasswdServer) startupOptions.getOptionValue(
+ PasswdServerOption.INNER_ADMIN_IMPL);
+ } else {
+ innerPasswdServer =
+ new DefaultInternalPasswdServerImpl(passwdServerSetting);
+ }
+
+ innerPasswdServer.init();
+ }
+
+ /**
+ * Start the Passwd passwd.
+ *
+ * @throws KrbException e.
+ */
+ public void start() throws KrbException {
+ if (innerPasswdServer == null) {
+ throw new RuntimeException("Not init yet");
+ }
+ innerPasswdServer.start();
+ }
+
+ /**
+ * Stop the Passwd passwd.
+ *
+ * @throws KrbException e.
+ */
+ public void stop() throws KrbException {
+ if (innerPasswdServer != null) {
+ innerPasswdServer.stop();
+ }
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfig.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfig.java
new file mode 100644
index 0000000..4cb89f2
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfig.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.kerberos.kerb.admin.server.kpasswd;
+
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb KDC side configuration API.
+ */
+public class PasswdServerConfig extends Krb5Conf {
+ private static final String KDCDEFAULT = "passwddefaults";
+
+ public boolean enableDebug() {
+ return getBoolean(PasswdServerConfigKey.KRB_DEBUG, true, KDCDEFAULT);
+ }
+
+ public String getPasswdServiceName() {
+ return getString(PasswdServerConfigKey.ADMIN_SERVICE_NAME, true, KDCDEFAULT);
+ }
+
+ public String getPasswdHost() {
+ return getString(PasswdServerConfigKey.ADMIN_HOST, true, KDCDEFAULT);
+ }
+
+ public int getPasswdPort() {
+ Integer passwdPort = getInt(PasswdServerConfigKey.ADMIN_PORT, true, KDCDEFAULT);
+ if (passwdPort != null && passwdPort > 0) {
+ return passwdPort.intValue();
+ }
+ return -1;
+ }
+
+ public int getPasswdTcpPort() {
+ Integer passwdTcpPort = getInt(PasswdServerConfigKey.ADMIN_TCP_PORT, true, KDCDEFAULT);
+ if (passwdTcpPort != null && passwdTcpPort > 0) {
+ return passwdTcpPort.intValue();
+ }
+ return getPasswdPort();
+ }
+
+ /**
+ * Is to allow TCP for KDC
+ * @return true to allow TCP, false otherwise
+ */
+ public Boolean allowTcp() {
+ return getBoolean(PasswdServerConfigKey.ADMIN_ALLOW_TCP, true, KDCDEFAULT)
+ || getInt(PasswdServerConfigKey.ADMIN_TCP_PORT, true, KDCDEFAULT) != null
+ || getInt(PasswdServerConfigKey.ADMIN_PORT, false, KDCDEFAULT) != null;
+ }
+
+ /**
+ * Is to allow UDP for KDC
+ * @return true to allow UDP, false otherwise
+ */
+ public Boolean allowUdp() {
+ return getBoolean(PasswdServerConfigKey.ADMIN_ALLOW_UDP, true, KDCDEFAULT)
+ || getInt(PasswdServerConfigKey.ADMIN_UDP_PORT, true, KDCDEFAULT) != null
+ || getInt(PasswdServerConfigKey.ADMIN_PORT, false, KDCDEFAULT) != null;
+ }
+
+ public int getPasswdUdpPort() {
+ Integer passwdUdpPort = getInt(PasswdServerConfigKey.ADMIN_UDP_PORT, true, KDCDEFAULT);
+ if (passwdUdpPort != null && passwdUdpPort > 0) {
+ return passwdUdpPort.intValue();
+ }
+ return getPasswdPort();
+ }
+
+ public String getPasswdRealm() {
+ return getString(PasswdServerConfigKey.ADMIN_REALM, true, KDCDEFAULT);
+ }
+
+ public String getPasswdDomain() {
+ return getString(PasswdServerConfigKey.ADMIN_DOMAIN, true, KDCDEFAULT);
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfigKey.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfigKey.java
new file mode 100644
index 0000000..8f7651e
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfigKey.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.server.kpasswd;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum PasswdServerConfigKey implements ConfigKey {
+ KRB_DEBUG(true),
+ ADMIN_SERVICE_NAME("Kpasswd-Server"),
+ KDC_IDENTITY_BACKEND,
+ ADMIN_HOST("127.0.0.1"),
+ ADMIN_PORT,
+ ADMIN_ALLOW_TCP(true),
+ ADMIN_ALLOW_UDP(true),
+ ADMIN_UDP_PORT,
+ ADMIN_TCP_PORT,
+ ADMIN_DOMAIN("example.com"),
+ ADMIN_REALM("EXAMPLE.COM");
+
+ private Object defaultValue;
+
+ PasswdServerConfigKey() {
+ this.defaultValue = null;
+ }
+
+ PasswdServerConfigKey(Object defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ @Override
+ public String getPropertyKey() {
+ return name().toLowerCase();
+ }
+
+ @Override
+ public Object getDefaultValue() {
+ return this.defaultValue;
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerContext.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerContext.java
new file mode 100644
index 0000000..0d4bc7e
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerContext.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.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.identity.IdentityService;
+
+public class PasswdServerContext {
+ private final PasswdServerSetting passwdServerSetting;
+
+ private IdentityService identityService;
+
+ public PasswdServerContext(PasswdServerSetting passwdServerSetting) {
+ this.passwdServerSetting = passwdServerSetting;
+ }
+
+ public PasswdServerSetting getPasswdServerSetting() {
+ return passwdServerSetting;
+ }
+
+ public PasswdServerConfig getConfig() {
+ return passwdServerSetting.getPasswdServerConfig();
+ }
+
+ public void setIdentityService(IdentityService identityService) {
+ this.identityService = identityService;
+ }
+
+ public IdentityService getIdentityService() {
+ return identityService;
+ }
+
+ public String getPasswdRealm() {
+ return passwdServerSetting.getPasswdRealm();
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerHandler.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerHandler.java
new file mode 100644
index 0000000..363ecdd
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerHandler.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.server.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+/**
+ * KDC handler to process client requests. Currently only one realm is supported.
+ */
+public class PasswdServerHandler {
+ private static final Logger LOG = LoggerFactory.getLogger(PasswdServerHandler.class);
+ private final PasswdServerContext passwdServerContext;
+
+ /**
+ * Constructor with passwd context.
+ *
+ * @param passwdServerContext passwd passwd context
+ */
+ public PasswdServerHandler(PasswdServerContext passwdServerContext) {
+ this.passwdServerContext = passwdServerContext;
+ LOG.info("Passwd context realm:" + this.passwdServerContext.getPasswdRealm());
+ }
+
+ /**
+ * 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 {
+ System.out.println("Password Server receive message: ");
+ System.out.println(new String(receivedMessage.array()));
+ String response = "Password server receive message.";
+ ByteBuffer responseMessage = ByteBuffer.allocate(response.length() + 4);
+ responseMessage.putInt(response.length());
+ responseMessage.put(response.getBytes());
+ responseMessage.flip();
+ return responseMessage;
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerImpl.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerImpl.java
new file mode 100644
index 0000000..7cd7a8b
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerImpl.java
@@ -0,0 +1,250 @@
+/**
+ * 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.kpasswd;
+
+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.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcServerOption;
+import org.apache.kerby.kerberos.kerb.server.KdcSetting;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.server.impl.DefaultInternalKdcServerImpl;
+import org.apache.kerby.kerberos.kerb.server.impl.InternalKdcServer;
+
+import java.io.File;
+
+/**
+ * The implemented Kerberos Server API.
+ */
+public class PasswdServerImpl {
+ private final KdcConfig passwdConfig;
+ private final BackendConfig backendConfig;
+ private final KdcSetting passwdSetting;
+ private final KOptions startupOptions;
+
+ private InternalKdcServer innerKdc;
+
+ /**
+ * Constructor passing both passwdConfig and backendConfig.
+ * @param passwdConfig The passwd config
+ * @param backendConfig The backend config
+ * @throws KrbException e
+ */
+ public PasswdServerImpl(KdcConfig passwdConfig,
+ BackendConfig backendConfig) throws KrbException {
+ this.passwdConfig = passwdConfig;
+ this.backendConfig = backendConfig;
+ startupOptions = new KOptions();
+ passwdSetting = new KdcSetting(startupOptions, passwdConfig, backendConfig);
+ }
+
+ /**
+ * Constructor given confDir where 'passwd.conf' and 'backend.conf' should be
+ * available.
+ * passwd.conf, that contains passwd passwd related items.
+ * backend.conf, that contains identity backend related items.
+ *
+ * @param confDir The conf dir
+ * @throws KrbException e
+ */
+ public PasswdServerImpl(File confDir) throws KrbException {
+ KdcConfig tmpKdcConfig = KdcUtil.getKdcConfig(confDir);
+ if (tmpKdcConfig == null) {
+ tmpKdcConfig = new KdcConfig();
+ }
+ this.passwdConfig = tmpKdcConfig;
+
+ BackendConfig tmpBackendConfig = KdcUtil.getBackendConfig(confDir);
+ if (tmpBackendConfig == null) {
+ tmpBackendConfig = new BackendConfig();
+ }
+ tmpBackendConfig.setConfDir(confDir);
+ this.backendConfig = tmpBackendConfig;
+
+ startupOptions = new KOptions();
+ passwdSetting = new KdcSetting(startupOptions, passwdConfig, backendConfig);
+ }
+
+ /**
+ * Default constructor.
+ */
+ public PasswdServerImpl() {
+ passwdConfig = new KdcConfig();
+ backendConfig = new BackendConfig();
+ startupOptions = new KOptions();
+ passwdSetting = new KdcSetting(startupOptions, passwdConfig, backendConfig);
+ }
+
+ /**
+ * Set KDC realm for ticket request
+ * @param realm The passwd realm
+ */
+ public void setKdcRealm(String realm) {
+ startupOptions.add(KdcServerOption.KDC_REALM, realm);
+ }
+
+ /**
+ * Set KDC host.
+ * @param passwdHost The passwd host
+ */
+ public void setKdcHost(String passwdHost) {
+ startupOptions.add(KdcServerOption.KDC_HOST, passwdHost);
+ }
+
+ /**
+ * Set KDC port.
+ * @param passwdPort The passwd port
+ */
+ public void setKdcPort(int passwdPort) {
+ startupOptions.add(KdcServerOption.KDC_PORT, passwdPort);
+ }
+
+ /**
+ * Set KDC tcp port.
+ * @param passwdTcpPort The passwd tcp port
+ */
+ public void setKdcTcpPort(int passwdTcpPort) {
+ startupOptions.add(KdcServerOption.KDC_TCP_PORT, passwdTcpPort);
+ }
+
+ /**
+ * Set to allow UDP or not.
+ * @param allowUdp true if allow udp
+ */
+ public void setAllowUdp(boolean allowUdp) {
+ startupOptions.add(KdcServerOption.ALLOW_UDP, allowUdp);
+ }
+
+ /**
+ * Set to allow TCP or not.
+ * @param allowTcp true if allow tcp
+ */
+ public void setAllowTcp(boolean allowTcp) {
+ startupOptions.add(KdcServerOption.ALLOW_TCP, allowTcp);
+ }
+ /**
+ * Set KDC udp port. Only makes sense when allowUdp is set.
+ * @param passwdUdpPort The passwd udp port
+ */
+ public void setKdcUdpPort(int passwdUdpPort) {
+ startupOptions.add(KdcServerOption.KDC_UDP_PORT, passwdUdpPort);
+ }
+
+ /**
+ * Set runtime folder.
+ * @param workDir The work dir
+ */
+ public void setWorkDir(File workDir) {
+ startupOptions.add(KdcServerOption.WORK_DIR, workDir);
+ }
+
+ /**
+ * Allow to debug so have more logs.
+ */
+ public void enableDebug() {
+ startupOptions.add(KdcServerOption.ENABLE_DEBUG);
+ }
+
+ /**
+ * Allow to hook customized passwd implementation.
+ *
+ * @param innerKdcImpl The inner passwd implementation
+ */
+ public void setInnerKdcImpl(InternalKdcServer innerKdcImpl) {
+ startupOptions.add(KdcServerOption.INNER_KDC_IMPL, innerKdcImpl);
+ }
+
+ /**
+ * Get KDC setting from startup options and configs.
+ * @return setting
+ */
+ public KdcSetting getKdcSetting() {
+ return passwdSetting;
+ }
+
+ /**
+ * Get the KDC config.
+ * @return PasswdServerConfig
+ */
+ public KdcConfig getKdcConfig() {
+ return passwdConfig;
+ }
+
+ /**
+ * Get backend config.
+ *
+ * @return backend configuration
+ */
+ public BackendConfig getBackendConfig() {
+ return backendConfig;
+ }
+
+ /**
+ * Get identity service.
+ * @return IdentityService
+ */
+ public IdentityBackend getIdentityService() {
+ if (innerKdc == null) {
+ throw new RuntimeException("Not init yet");
+ }
+ return innerKdc.getIdentityBackend();
+ }
+
+ /**
+ * Initialize.
+ *
+ * @throws KrbException e.
+ */
+ public void init() throws KrbException {
+ if (startupOptions.contains(KdcServerOption.INNER_KDC_IMPL)) {
+ innerKdc = (InternalKdcServer) startupOptions.getOptionValue(
+ KdcServerOption.INNER_KDC_IMPL);
+ } else {
+ innerKdc = new DefaultInternalKdcServerImpl(passwdSetting);
+ }
+
+ innerKdc.init();
+ }
+
+ /**
+ * Start the KDC passwd.
+ *
+ * @throws KrbException e.
+ */
+ public void start() throws KrbException {
+ if (innerKdc == null) {
+ throw new RuntimeException("Not init yet");
+ }
+ innerKdc.start();
+ }
+
+ /**
+ * Stop the KDC passwd.
+ *
+ * @throws KrbException e.
+ */
+ public void stop() throws KrbException {
+ if (innerKdc != null) {
+ innerKdc.stop();
+ }
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerOption.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerOption.java
new file mode 100644
index 0000000..4594b14
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerOption.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.kpasswd;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * KDC passwd startup options
+ */
+public enum PasswdServerOption implements KOption {
+ NONE(null),
+ INNER_ADMIN_IMPL(new KOptionInfo("inner KDC impl", "inner KDC impl", KOptionType.OBJ)),
+ ADMIN_REALM(new KOptionInfo("passwd realm", "passwd realm", KOptionType.STR)),
+ ADMIN_HOST(new KOptionInfo("passwd host", "passwd host", KOptionType.STR)),
+ ADMIN_PORT(new KOptionInfo("passwd port", "passwd port", KOptionType.INT)),
+ ALLOW_TCP(new KOptionInfo("allow tcp", "allow tcp", KOptionType.BOOL)),
+ ADMIN_TCP_PORT(new KOptionInfo("passwd tcp port", "passwd tcp port", KOptionType.INT)),
+ ALLOW_UDP(new KOptionInfo("allow udp", "allow udp", KOptionType.BOOL)),
+ ADMIN_UDP_PORT(new KOptionInfo("passwd udp port", "passwd 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;
+
+ PasswdServerOption(KOptionInfo optionInfo) {
+ this.optionInfo = optionInfo;
+ }
+
+ @Override
+ public KOptionInfo getOptionInfo() {
+ return optionInfo;
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerSetting.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerSetting.java
new file mode 100644
index 0000000..9316104
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerSetting.java
@@ -0,0 +1,188 @@
+/**
+ * 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.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+
+/**
+ * Passwd Server setting that combines startup options and passwd config.
+ */
+public class PasswdServerSetting {
+ private final KOptions startupOptions;
+ private final PasswdServerConfig passwdServerConfig;
+ private final BackendConfig backendConfig;
+
+ /**
+ * PasswdServerSetting constructor
+ * @param startupOptions startup options
+ * @param config passwd configuration
+ * @param backendConfig backend configuration
+ */
+ public PasswdServerSetting(KOptions startupOptions,
+ PasswdServerConfig config,
+ BackendConfig backendConfig) {
+ this.startupOptions = startupOptions;
+ this.passwdServerConfig = config;
+ this.backendConfig = backendConfig;
+ }
+
+ public PasswdServerSetting(PasswdServerConfig passwdServerConfig,
+ BackendConfig backendConfig) {
+ this(new KOptions(), passwdServerConfig, backendConfig);
+ }
+
+ /**
+ * Get the Passwd Server config.
+ * @return passwd configuration
+ */
+ public PasswdServerConfig getPasswdServerConfig() {
+ return passwdServerConfig;
+ }
+
+ /**
+ * Get the backend config.
+ * @return backend configuration
+ */
+ public BackendConfig getBackendConfig() {
+ return backendConfig;
+ }
+
+ public String getPasswdHost() {
+ String passwdHost = startupOptions.getStringOption(
+ PasswdServerOption.ADMIN_HOST);
+ if (passwdHost == null) {
+ passwdHost = passwdServerConfig.getPasswdHost();
+ }
+ return passwdHost;
+ }
+
+ /**
+ * Check passwd tcp setting and see if any bad.
+ * @return valid tcp port or -1 if not allowTcp
+ * @throws KrbException e
+ */
+ public int checkGetPasswdTcpPort() throws KrbException {
+ if (allowTcp()) {
+ int passwdPort = getPasswdTcpPort();
+ if (passwdPort < 1) {
+ throw new KrbException("Passwd Server tcp port isn't set or configured");
+ }
+ return passwdPort;
+ }
+ return -1;
+ }
+
+ /**
+ * Check passwd udp setting and see if any bad.
+ * @return valid udp port or -1 if not allowUdp
+ * @throws KrbException e
+ */
+ public int checkGetPasswdUdpPort() throws KrbException {
+ if (allowUdp()) {
+ int passwdPort = getPasswdUdpPort();
+ if (passwdPort < 1) {
+ throw new KrbException("Passwd Server udp port isn't set or configured");
+ }
+ return passwdPort;
+ }
+ return -1;
+ }
+
+ /**
+ * Get passwd tcp port
+ *
+ * @return passwd tcp port
+ */
+ public int getPasswdTcpPort() {
+ int tcpPort = startupOptions.getIntegerOption(PasswdServerOption.ADMIN_TCP_PORT);
+ if (tcpPort < 1) {
+ tcpPort = passwdServerConfig.getPasswdTcpPort();
+ }
+ if (tcpPort < 1) {
+ tcpPort = getPasswdPort();
+ }
+
+ return tcpPort;
+ }
+
+ /**
+ * Get passwd port
+ *
+ * @return passwd port
+ */
+ public int getPasswdPort() {
+ int passwdPort = startupOptions.getIntegerOption(PasswdServerOption.ADMIN_PORT);
+ if (passwdPort < 1) {
+ passwdPort = passwdServerConfig.getPasswdPort();
+ }
+ return passwdPort;
+ }
+
+ /**
+ * Get whether tcp protocol is allowed
+ * @return tcp protocol is allowed or not
+ */
+ public boolean allowTcp() {
+ Boolean allowTcp = startupOptions.getBooleanOption(
+ PasswdServerOption.ALLOW_TCP, passwdServerConfig.allowTcp());
+ return allowTcp;
+ }
+
+ /**
+ * Get whether udp protocol is allowed
+ * @return udp protocol is allowed or not
+ */
+ public boolean allowUdp() {
+ Boolean allowUdp = startupOptions.getBooleanOption(
+ PasswdServerOption.ALLOW_UDP, passwdServerConfig.allowUdp());
+ return allowUdp;
+ }
+
+ /**
+ * Get passwd udp port
+ *
+ * @return udp port
+ */
+ public int getPasswdUdpPort() {
+ int udpPort = startupOptions.getIntegerOption(PasswdServerOption.ADMIN_UDP_PORT);
+ if (udpPort < 1) {
+ udpPort = passwdServerConfig.getPasswdUdpPort();
+ }
+ if (udpPort < 1) {
+ udpPort = getPasswdPort();
+ }
+
+ return udpPort;
+ }
+
+ /**
+ * Get Passwd Server realm.
+ * @return Passwd Server realm
+ */
+ public String getPasswdRealm() {
+ String passwdRealm = startupOptions.getStringOption(PasswdServerOption.ADMIN_REALM);
+ if (passwdRealm == null || passwdRealm.isEmpty()) {
+ passwdRealm = passwdServerConfig.getPasswdRealm();
+ }
+ return passwdRealm;
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerUtil.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerUtil.java
new file mode 100644
index 0000000..f45bafa
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerUtil.java
@@ -0,0 +1,142 @@
+/**
+ * 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.kpasswd;
+
+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.transport.TransportPair;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+/**
+ * KDC side utilities.
+ */
+public final class PasswdServerUtil {
+
+ private PasswdServerUtil() { }
+
+ /**
+ * Get passwd configuration
+ * @param confDir configuration directory
+ * @return passwd configuration
+ * @throws KrbException e.
+ */
+ public static PasswdServerConfig getPasswdServerConfig(File confDir) throws KrbException {
+ File passwdConfFile = new File(confDir, "kpasswdServer.conf");
+ if (passwdConfFile.exists()) {
+ PasswdServerConfig passwdServerConfig = new PasswdServerConfig();
+ try {
+ passwdServerConfig.addKrb5Config(passwdConfFile);
+ } catch (IOException e) {
+ throw new KrbException("Can not load the passwd configuration file "
+ + passwdConfFile.getAbsolutePath());
+ }
+ return passwdServerConfig;
+ }
+
+ 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(
+ PasswdServerConfigKey.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 passwd setting
+ * @return UDP and TCP addresses pair
+ * @throws KrbException e
+ */
+ public static TransportPair getTransportPair(
+ PasswdServerSetting setting) throws KrbException {
+ TransportPair result = new TransportPair();
+
+ int tcpPort = setting.checkGetPasswdTcpPort();
+ if (tcpPort > 0) {
+ result.tcpAddress = new InetSocketAddress(
+ setting.getPasswdHost(), tcpPort);
+ }
+ int udpPort = setting.checkGetPasswdUdpPort();
+ if (udpPort > 0) {
+ result.udpAddress = new InetSocketAddress(
+ setting.getPasswdHost(), udpPort);
+ }
+
+ return result;
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/AbstractInternalPasswdServer.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/AbstractInternalPasswdServer.java
new file mode 100644
index 0000000..0130f57
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/AbstractInternalPasswdServer.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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerConfig;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerSetting;
+import org.apache.kerby.kerberos.kerb.identity.CacheableIdentityService;
+import org.apache.kerby.kerberos.kerb.identity.IdentityService;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.MemoryIdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+
+/**
+ * Abstract Kpasswd passwd implementation.
+ */
+public class AbstractInternalPasswdServer implements InternalPasswdServer {
+ private boolean started;
+ private final PasswdServerConfig passwdConfig;
+ private final BackendConfig backendConfig;
+ private final PasswdServerSetting passwdSetting;
+ private IdentityBackend backend;
+ private IdentityService identityService;
+
+ public AbstractInternalPasswdServer(PasswdServerSetting passwdSetting) {
+ this.passwdSetting = passwdSetting;
+ this.passwdConfig = passwdSetting.getPasswdServerConfig();
+ this.backendConfig = passwdSetting.getBackendConfig();
+ }
+
+ @Override
+ public PasswdServerSetting getSetting() {
+ return passwdSetting;
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ protected String getServiceName() {
+ return passwdConfig.getPasswdServiceName();
+ }
+
+ 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 passwdConfig.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/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultInternalPasswdServerImpl.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultInternalPasswdServerImpl.java
new file mode 100644
index 0000000..f50a25b
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultInternalPasswdServerImpl.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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerContext;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerSetting;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerUtil;
+import org.apache.kerby.kerberos.kerb.transport.KdcNetwork;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * A default passwd passwd implementation.
+ */
+public class DefaultInternalPasswdServerImpl extends AbstractInternalPasswdServer {
+ private ExecutorService executor;
+ private PasswdServerContext passwdContext;
+ private KdcNetwork network;
+
+ public DefaultInternalPasswdServerImpl(PasswdServerSetting passwdSetting) {
+ super(passwdSetting);
+ }
+
+ @Override
+ protected void doStart() throws Exception {
+ super.doStart();
+
+ prepareHandler();
+
+ executor = Executors.newCachedThreadPool();
+
+ network = new KdcNetwork() {
+ @Override
+ protected void onNewTransport(KrbTransport transport) {
+ DefaultPasswdServerHandler passwdHandler =
+ new DefaultPasswdServerHandler(passwdContext, transport);
+ executor.execute(passwdHandler);
+ }
+ };
+
+ network.init();
+ TransportPair tpair = PasswdServerUtil.getTransportPair(getSetting());
+ network.listen(tpair);
+ network.start();
+ }
+
+ private void prepareHandler() {
+ passwdContext = new PasswdServerContext(getSetting());
+ passwdContext.setIdentityService(getIdentityService());
+ }
+
+ @Override
+ protected void doStop() throws Exception {
+ super.doStop();
+
+ network.stop();
+
+ executor.shutdownNow();
+ }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultPasswdServerHandler.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultPasswdServerHandler.java
new file mode 100644
index 0000000..f9bd6ce
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultPasswdServerHandler.java
@@ -0,0 +1,72 @@
+/**
+ * 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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerContext;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerHandler;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+public class DefaultPasswdServerHandler extends PasswdServerHandler implements Runnable {
+ private static Logger logger = LoggerFactory.getLogger(DefaultPasswdServerHandler.class);
+ private final KrbTransport transport;
+
+ public DefaultPasswdServerHandler(PasswdServerContext passwdServerContext, KrbTransport transport) {
+ super(passwdServerContext);
+ this.transport = transport;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ 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 krbResponse = handleMessage(message, clientAddress);
+ transport.sendMessage(krbResponse);
+ } catch (Exception e) {
+ transport.release();
+ logger.error("Error occured while processing request:", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/InternalPasswdServer.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/InternalPasswdServer.java
new file mode 100644
index 0000000..c84ddbb
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/InternalPasswdServer.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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerSetting;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+
+/**
+ * An internal KDC passwd interface.
+ */
+public interface InternalPasswdServer {
+
+ /**
+ * Initialize.
+ * @throws KrbException e
+ */
+ void init() throws KrbException;
+
+ /**
+ * Start the KDC passwd.
+ * @throws KrbException e
+ */
+ void start() throws KrbException;
+
+ /**
+ * Stop the KDC passwd.
+ * @throws KrbException e
+ */
+ void stop() throws KrbException;
+
+ /**
+ * Get passwd passwd setting.
+ * @return setting
+ */
+ PasswdServerSetting getSetting();
+
+ /**
+ * Get identity backend.
+ * @return IdentityBackend
+ */
+ IdentityBackend getIdentityBackend();
+}
diff --git a/kerby-dist/kdc-dist/bin/kpasswdClient.cmd b/kerby-dist/kdc-dist/bin/kpasswdClient.cmd
new file mode 100644
index 0000000..0ecd815
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdClient.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=8011,server=y,suspend=n
+ set args=%args:-D=%
+ )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=kpasswdClient ^
+org.apache.kerby.kerberos.kerb.admin.PasswdClientTool %args%
\ No newline at end of file
diff --git a/kerby-dist/kdc-dist/bin/kpasswdClient.sh b/kerby-dist/kdc-dist/bin/kpasswdClient.sh
new file mode 100644
index 0000000..a59e3d6
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdClient.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=8011,server=y,suspend=n"
+ else
+ args="$args $var"
+ fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=kpasswdClient \
+org.apache.kerby.kerberos.kerb.admin.PasswdClientTool $args
\ No newline at end of file
diff --git a/kerby-dist/kdc-dist/bin/kpasswdServer.cmd b/kerby-dist/kdc-dist/bin/kpasswdServer.cmd
new file mode 100644
index 0000000..27e091a
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdServer.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=8010,server=y,suspend=n
+ set args=%args:-D=%
+ )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=kpasswdServer ^
+org.apache.kerby.kerberos.kerb.admin.server.PasswdServerInit %args%
diff --git a/kerby-dist/kdc-dist/bin/kpasswdServer.sh b/kerby-dist/kdc-dist/bin/kpasswdServer.sh
new file mode 100644
index 0000000..97feb41
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdServer.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=8010,server=y,suspend=n"
+ else
+ args="$args $var"
+ fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=kpasswdServer \
+org.apache.kerby.kerberos.kerb.admin.server.PasswdServerInit $args
\ No newline at end of file
diff --git a/kerby-dist/kdc-dist/conf/kpasswdClient.conf b/kerby-dist/kdc-dist/conf/kpasswdClient.conf
new file mode 100644
index 0000000..ea59d8b
--- /dev/null
+++ b/kerby-dist/kdc-dist/conf/kpasswdClient.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 = 65418
diff --git a/kerby-dist/kdc-dist/conf/kpasswdServer.conf b/kerby-dist/kdc-dist/conf/kpasswdServer.conf
new file mode 100644
index 0000000..ea59d8b
--- /dev/null
+++ b/kerby-dist/kdc-dist/conf/kpasswdServer.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 = 65418
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/PasswdClientTool.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/PasswdClientTool.java
new file mode 100644
index 0000000..cdceb2d
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/PasswdClientTool.java
@@ -0,0 +1,88 @@
+/**
+ * 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.kpasswd.PasswdClient;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdConfig;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdHandler;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdUtil;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.impl.DefaultPasswdHandler;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.request.PasswdRequest;
+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 java.io.File;
+import java.io.IOException;
+
+/**
+ * A running tool for password client.
+ */
+public class PasswdClientTool {
+ private static final String USAGE = (OSUtil.isWindows()
+ ? "Usage: bin\\kpasswdClient.cmd" : "Usage: sh bin/kpasswdClient.sh")
+ + " <conf-file>\n"
+ + "\tExample:\n"
+ + "\t\t"
+ + (OSUtil.isWindows()
+ ? "bin\\kpasswdClient.cmd" : "sh bin/kpasswdClient.sh")
+ + " conf\n";
+
+ private static final String LEGAL_COMMANDS = "Legal functions are remaining to construct...\n";
+
+ public static void main(String[] args) throws KrbException {
+
+ if (args.length != 1) {
+ System.err.println(USAGE);
+ System.exit(1);
+ }
+
+ String confDirPath = args[0];
+ PasswdClient passwdClient = new PasswdClient(new File(confDirPath));
+ PasswdConfig passwdConfig = passwdClient.getPasswdConfig();
+
+ passwdClient.setAdminRealm(passwdConfig.getAdminRealm());
+ passwdClient.setAllowTcp(true);
+ passwdClient.setAllowUdp(true);
+ passwdClient.setAdminTcpPort(passwdConfig.getAdminPort());
+ passwdClient.setAdminUdpPort(passwdConfig.getAdminPort());
+
+ passwdClient.init();
+ System.out.println("password client init successful!");
+ System.out.print(LEGAL_COMMANDS);
+
+ PasswdHandler passwdHandler = new DefaultPasswdHandler();
+ PasswdRequest passwdRequest = new PasswdRequest();
+
+ TransportPair tpair = PasswdUtil.getTransportPair(passwdClient.getSetting());
+ KrbNetwork network = new KrbNetwork();
+ network.setSocketTimeout(passwdClient.getSetting().getTimeout());
+ KrbTransport transport;
+ try {
+ transport = network.connect(tpair);
+ } catch (IOException e) {
+ throw new KrbException("Failed to create transport", e);
+ }
+ passwdRequest.setTransport(transport);
+ passwdHandler.handleRequest(passwdRequest);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdClient.java
new file mode 100644
index 0000000..6861fa7
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdClient.java
@@ -0,0 +1,155 @@
+/**
+ * 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.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.impl.DefaultInternalPasswdClient;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.impl.InternalPasswdClient;
+
+import java.io.File;
+
+/**
+ * A Krb client API for applications to interact with KDC
+ */
+public class PasswdClient {
+
+ private final PasswdConfig passwdConfig;
+ private final KOptions commonOptions;
+ private final PasswdSetting passwdSetting;
+
+ private InternalPasswdClient innerClient;
+
+ /**
+ * Default constructor.
+ * @throws KrbException e
+ */
+ public PasswdClient() throws KrbException {
+ this.passwdConfig = PasswdUtil.getDefaultConfig();
+ this.commonOptions = new KOptions();
+ this.passwdSetting = new PasswdSetting(commonOptions, passwdConfig);
+ }
+
+ /**
+ * Construct with prepared PasswdConfig.
+ * @param passwdConfig The krb config
+ */
+ public PasswdClient(PasswdConfig passwdConfig) {
+ this.passwdConfig = passwdConfig;
+ this.commonOptions = new KOptions();
+ this.passwdSetting = new PasswdSetting(commonOptions, passwdConfig);
+ }
+
+ /**
+ * Constructor with conf dir
+ * @param confDir The conf dir
+ * @throws KrbException e
+ */
+ public PasswdClient(File confDir) throws KrbException {
+ this.commonOptions = new KOptions();
+ this.passwdConfig = PasswdUtil.getConfig(confDir);
+ this.passwdSetting = new PasswdSetting(commonOptions, passwdConfig);
+ }
+
+ /**
+ * Set KDC realm for ticket request
+ * @param realm The realm
+ */
+ public void setAdminRealm(String realm) {
+ commonOptions.add(PasswdOption.ADMIN_REALM, realm);
+ }
+
+ /**
+ * Set Admin Server host.
+ * @param kdcHost The kdc host
+ */
+ public void setKdcHost(String kdcHost) {
+ commonOptions.add(PasswdOption.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(PasswdOption.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(PasswdOption.ALLOW_UDP, allowUdp);
+ }
+
+ /**
+ * Set to allow TCP or not.
+ * @param allowTcp true if allow tcp
+ */
+ public void setAllowTcp(boolean allowTcp) {
+ commonOptions.add(PasswdOption.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(PasswdOption.ADMIN_UDP_PORT, adminUdpPort);
+ setAllowUdp(true);
+ }
+
+ /**
+ * Set time out for connection
+ * @param timeout in seconds
+ */
+ public void setTimeout(int timeout) {
+ commonOptions.add(PasswdOption.CONN_TIMEOUT, timeout);
+ }
+
+ /**
+ * Init the client.
+ * @throws KrbException e
+ */
+ public void init() throws KrbException {
+ innerClient = new DefaultInternalPasswdClient(passwdSetting);
+ innerClient.init();
+ }
+
+ /**
+ * Get krb client settings from options and configs.
+ * @return setting
+ */
+ public PasswdSetting getSetting() {
+ return passwdSetting;
+ }
+
+ public PasswdConfig getPasswdConfig() {
+ return passwdConfig;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfig.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfig.java
new file mode 100644
index 0000000..583ccf6
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfig.java
@@ -0,0 +1,120 @@
+/**
+ * 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.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb client side configuration API.
+ */
+public class PasswdConfig extends Krb5Conf {
+ private static final String LIBDEFAULT = "libdefaults";
+
+ public boolean enableDebug() {
+ return getBoolean(PasswdConfigKey.KRB_DEBUG, true, LIBDEFAULT);
+ }
+
+ /**
+ * Get KDC host name
+ *
+ * @return The kdc host
+ */
+ public String getAdminHost() {
+ return getString(
+ PasswdConfigKey.ADMIN_HOST, true, LIBDEFAULT);
+ }
+
+ /**
+ * Get KDC port, as both TCP and UDP ports
+ *
+ * @return The kdc host
+ */
+ public int getAdminPort() {
+ Integer kdcPort = getInt(PasswdConfigKey.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(PasswdConfigKey.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(PasswdConfigKey.ADMIN_ALLOW_UDP, true, LIBDEFAULT)
+ || getInt(PasswdConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT) != null
+ || getInt(PasswdConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+ }
+
+ /**
+ * Is to allow TCP for KDC
+ *
+ * @return true to allow TCP, false otherwise
+ */
+ public boolean allowTcp() {
+ return getBoolean(PasswdConfigKey.ADMIN_ALLOW_TCP, true, LIBDEFAULT)
+ || getInt(PasswdConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT) != null
+ || getInt(PasswdConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+ }
+
+ /**
+ * Get KDC UDP port
+ *
+ * @return The kdc udp port
+ */
+ public int getAdminUdpPort() {
+ Integer kdcPort = getInt(PasswdConfigKey.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(PasswdConfigKey.ADMIN_REALM, false, LIBDEFAULT);
+ if (realm == null) {
+ realm = getString(PasswdConfigKey.DEFAULT_REALM, false, LIBDEFAULT);
+ if (realm == null) {
+ realm = (String) PasswdConfigKey.ADMIN_REALM.getDefaultValue();
+ }
+ }
+
+ return realm;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfigKey.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfigKey.java
new file mode 100644
index 0000000..b963076
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfigKey.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.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum PasswdConfigKey implements ConfigKey {
+ KRB_DEBUG(true),
+ ADMIN_HOST("localhost"),
+ ADMIN_PORT(null),
+ ADMIN_ALLOW_UDP(true),
+ ADMIN_ALLOW_TCP(true),
+ ADMIN_UDP_PORT(null),
+ ADMIN_TCP_PORT(null),
+ ADMIN_DOMAIN("example.com"),
+ DEFAULT_REALM(null),
+ ADMIN_REALM("EXAMPLE.COM");
+
+ private Object defaultValue;
+
+ PasswdConfigKey() {
+ this.defaultValue = null;
+ }
+
+ PasswdConfigKey(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/kpasswd/PasswdContext.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdContext.java
new file mode 100644
index 0000000..16837d9
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdContext.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.kpasswd;
+
+public class PasswdContext {
+
+ private PasswdSetting passwdSetting;
+
+ /**
+ * Init with krbsetting.
+ * @param passwdSetting The krb setting
+ */
+ public void init(PasswdSetting passwdSetting) {
+ this.passwdSetting = passwdSetting;
+ }
+
+ /**
+ * Get krbsetting.
+ * @return The krb setting
+ */
+ public PasswdSetting getPasswdSetting() {
+ return passwdSetting;
+ }
+
+ /**
+ * Get krbconfig.
+ * @return The krb config
+ */
+ public PasswdConfig getConfig() {
+ return passwdSetting.getPasswdConfig();
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdHandler.java
new file mode 100644
index 0000000..8f07bbc
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdHandler.java
@@ -0,0 +1,84 @@
+/**
+ * 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.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.request.PasswdRequest;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public abstract class PasswdHandler {
+
+ /**
+ * Init with krbcontext.
+ *
+ * @param context The krbcontext
+ */
+ public void init(PasswdContext context) {
+
+ }
+
+ /**
+ * Handle the password server request.
+ *
+ * @param passwdRequest The password server request
+ * @throws KrbException e
+ */
+ public void handleRequest(PasswdRequest passwdRequest) throws KrbException {
+ passwdRequest.process();
+
+ String request = "Client request change password.";
+ ByteBuffer requestMessage = ByteBuffer.allocate(request.length() + 4);
+ requestMessage.putInt(request.length());
+ requestMessage.put(request.getBytes());
+ requestMessage.flip();
+
+ try {
+ sendMessage(passwdRequest, requestMessage);
+ } catch (IOException e) {
+ throw new KrbException("sending message failed", e);
+ }
+ }
+
+ /**
+ * Process the response message from kdc.
+ *
+ * @param passwdRequest The kpasswd request
+ * @param responseMessage The message from kdc
+ * @throws KrbException e
+ */
+ public void onResponseMessage(PasswdRequest passwdRequest,
+ ByteBuffer responseMessage) throws KrbException {
+ String message = new String(responseMessage.array());
+ System.out.println("client receive message: ");
+ System.out.println(message);
+ }
+
+ /**
+ * Send message to password server.
+ *
+ * @param passwdRequest The change password request
+ * @param requestMessage The request message to password server
+ * @throws IOException e
+ */
+ protected abstract void sendMessage(PasswdRequest passwdRequest,
+ ByteBuffer requestMessage) throws IOException;
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdOption.java
new file mode 100644
index 0000000..228733b
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdOption.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.kpasswd;
+
+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 PasswdOption 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;
+
+ PasswdOption(KOptionInfo optionInfo) {
+ this.optionInfo = optionInfo;
+ }
+
+ @Override
+ public KOptionInfo getOptionInfo() {
+ return optionInfo;
+ }
+
+ public static PasswdOption fromOptionName(String optionName) {
+ if (optionName != null) {
+ for (PasswdOption 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/kpasswd/PasswdSetting.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdSetting.java
new file mode 100644
index 0000000..56aa030
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdSetting.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.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Admin client setting that combines common options and client config.
+ */
+public class PasswdSetting {
+ private final KOptions commonOptions;
+ private final PasswdConfig passwdConfig;
+
+ public PasswdSetting(KOptions commonOptions, PasswdConfig config) {
+ this.commonOptions = commonOptions;
+ this.passwdConfig = config;
+ }
+
+ public PasswdSetting(PasswdConfig config) {
+ this.commonOptions = new KOptions();
+ this.passwdConfig = config;
+ }
+
+ public PasswdConfig getPasswdConfig() {
+ return passwdConfig;
+ }
+
+ public String getKdcRealm() {
+ String kdcRealm = commonOptions.getStringOption(PasswdOption.ADMIN_REALM);
+ if (kdcRealm == null || kdcRealm.isEmpty()) {
+ kdcRealm = passwdConfig.getAdminRealm();
+ }
+ return kdcRealm;
+ }
+
+ public String getKdcHost() {
+ String kdcHost = commonOptions.getStringOption(PasswdOption.ADMIN_HOST);
+ if (kdcHost == null) {
+ return passwdConfig.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(PasswdOption.ADMIN_TCP_PORT);
+ if (tcpPort > 0) {
+ return tcpPort;
+ }
+ return passwdConfig.getAdminTcpPort();
+ }
+
+ public boolean allowUdp() {
+ Boolean allowUdp = commonOptions.getBooleanOption(
+ PasswdOption.ALLOW_UDP, passwdConfig.allowUdp());
+ return allowUdp;
+ }
+
+ public boolean allowTcp() {
+ Boolean allowTcp = commonOptions.getBooleanOption(
+ PasswdOption.ALLOW_TCP, passwdConfig.allowTcp());
+ return allowTcp;
+ }
+
+ public int getKdcUdpPort() {
+ int udpPort = commonOptions.getIntegerOption(PasswdOption.ADMIN_UDP_PORT);
+ if (udpPort > 0) {
+ return udpPort;
+ }
+ return passwdConfig.getAdminUdpPort();
+ }
+
+ public int getTimeout() {
+ int timeout = commonOptions.getIntegerOption(PasswdOption.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/kpasswd/PasswdUtil.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdUtil.java
new file mode 100644
index 0000000..8843b74
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdUtil.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.kpasswd;
+
+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 PasswdUtil {
+ private PasswdUtil() { }
+
+ private static final String KRB5_FILE_NAME = "kpasswdClient.conf";
+ private static final String KRB5_ENV_NAME = "KRB5_CONFIG";
+
+ /**
+ * Load krb5.conf from specified conf dir.
+ * @param confDir The conf dir
+ * @return PasswdConfig
+ * @throws KrbException e
+ */
+ public static PasswdConfig 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()) {
+ PasswdConfig adminConfig = new PasswdConfig();
+ 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 PasswdConfig
+ * @throws KrbException e
+ */
+ public static PasswdConfig 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");
+ }
+ }
+
+ PasswdConfig adminConfig = new PasswdConfig();
+ 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(
+ PasswdSetting 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/kpasswd/impl/AbstractInternalPasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/AbstractInternalPasswdClient.java
new file mode 100644
index 0000000..675c93e
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/AbstractInternalPasswdClient.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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdSetting;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdContext;
+
+/**
+ * A krb client API for applications to interact with KDC
+ */
+public abstract class AbstractInternalPasswdClient
+ implements InternalPasswdClient {
+ private PasswdContext context;
+ private final PasswdSetting passwdSetting;
+
+ public AbstractInternalPasswdClient(PasswdSetting passwdSetting) {
+ this.passwdSetting = passwdSetting;
+ }
+
+ protected PasswdContext getContext() {
+ return context;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PasswdSetting getSetting() {
+ return passwdSetting;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init() throws KrbException {
+ context = new PasswdContext();
+ context.init(passwdSetting);
+ }
+
+ /**
+ * Fix principal name.
+ *
+ * @param principal The principal name
+ * @return The fixed principal
+ */
+ protected String fixPrincipal(String principal) {
+ if (!principal.contains("@")) {
+ principal += "@" + passwdSetting.getKdcRealm();
+ }
+ return principal;
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultInternalPasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultInternalPasswdClient.java
new file mode 100644
index 0000000..561de7c
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultInternalPasswdClient.java
@@ -0,0 +1,64 @@
+/**
+ * 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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdSetting;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdUtil;
+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 DefaultInternalPasswdClient extends AbstractInternalPasswdClient {
+
+ private DefaultPasswdHandler passwdHandler;
+ private KrbTransport transport;
+
+ public DefaultInternalPasswdClient(PasswdSetting krbSetting) {
+ super(krbSetting);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void init() throws KrbException {
+ super.init();
+
+ this.passwdHandler = new DefaultPasswdHandler();
+ passwdHandler.init(getContext());
+
+ TransportPair tpair = PasswdUtil.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);
+ } finally {
+ transport.release();
+ }
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultPasswdHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultPasswdHandler.java
new file mode 100644
index 0000000..dc82983
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultPasswdHandler.java
@@ -0,0 +1,61 @@
+/**
+ * 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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdHandler;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.request.PasswdRequest;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class DefaultPasswdHandler extends PasswdHandler {
+
+ /**
+ * Client handle request.
+ * Use super.handleRequest to send message,
+ * and use this.handleRequest to receive message.
+ */
+ @Override
+ public void handleRequest(PasswdRequest passwdRequest) throws KrbException {
+ /** super is used to send messsage*/
+ super.handleRequest(passwdRequest);
+
+ KrbTransport transport = passwdRequest.getTransport();
+ ByteBuffer receiveMessage = null;
+ try {
+ receiveMessage = transport.receiveMessage();
+ } catch (IOException e) {
+ throw new KrbException("Client receives response message failed.");
+ }
+ super.onResponseMessage(passwdRequest, receiveMessage);
+ }
+
+ /**
+ * Override super's sendMessage method.
+ */
+ @Override
+ protected void sendMessage(PasswdRequest passwdRequest,
+ ByteBuffer requestMessage) throws IOException {
+ KrbTransport transport = passwdRequest.getTransport();
+ transport.sendMessage(requestMessage);
+ }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/InternalPasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/InternalPasswdClient.java
new file mode 100644
index 0000000..55f30c2
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/InternalPasswdClient.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.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdSetting;
+
+/**
+ * An internal krb client interface.
+ */
+public interface InternalPasswdClient {
+
+ /**
+ * Init with all the necessary options.
+ * @throws KrbException e
+ */
+ void init() throws KrbException;
+
+ /**
+ * Get krb client settings.
+ * @return setting
+ */
+ PasswdSetting getSetting();
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/request/PasswdRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/request/PasswdRequest.java
new file mode 100644
index 0000000..7f8868c
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/request/PasswdRequest.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.kpasswd.request;
+
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+/**
+ * There is only one kind of password request,
+ * that is the change password request.
+ */
+public class PasswdRequest {
+ private KrbTransport transport;
+
+ public void setTransport(KrbTransport transport) {
+ this.transport = transport;
+ }
+
+ public KrbTransport getTransport() {
+ return transport;
+ }
+
+ public void process() {
+
+ }
+}
\ No newline at end of file