Break down KrbOption into 4 ones: KrbOption, KrbKdcOption, TokenOption, PkinitOption
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
index d152aa4..e0a6634 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
@@ -20,148 +20,55 @@
 package org.apache.kerby.kerberos.kerb.admin;
 
 import org.apache.kerby.KOption;
-import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
 import org.apache.kerby.KOptionType;
 
 public enum KadminOption implements KOption {
-    NONE("NONE"),
-    EXPIRE("-expire", "expire time", KOptionType.DATE),
-    DISABLED("-disabled", "disabled", KOptionType.BOOL),
-    LOCKED("-locked", "locked", KOptionType.BOOL),
-    FORCE("-force", "force", KOptionType.NOV),
-    KVNO("-kvno", "initial key version number", KOptionType.INT),
-    PW("-pw", "password", KOptionType.STR),
-    RANDKEY("-randkey", "random key", KOptionType.NOV),
-    KEEPOLD("-keepold", "keep old passowrd", KOptionType.NOV),
-    KEYSALTLIST("-e", "key saltlist", KOptionType.STR),
-    K("-k", "keytab file path", KOptionType.STR),
-    KEYTAB("-keytab", "keytab file path", KOptionType.STR),
-    CCACHE("-c", "credentials cache", KOptionType.FILE);
+    NONE(null),
+    EXPIRE(new KOptionInfo("-expire", "expire time", KOptionType.DATE)),
+    DISABLED(new KOptionInfo("-disabled", "disabled", KOptionType.BOOL)),
+    LOCKED(new KOptionInfo("-locked", "locked", KOptionType.BOOL)),
+    FORCE(new KOptionInfo("-force", "force", KOptionType.NOV)),
+    KVNO(new KOptionInfo("-kvno", "initial key version number", KOptionType.INT)),
+    PW(new KOptionInfo("-pw", "password", KOptionType.STR)),
+    RANDKEY(new KOptionInfo("-randkey", "random key", KOptionType.NOV)),
+    KEEPOLD(new KOptionInfo("-keepold", "keep old passowrd", KOptionType.NOV)),
+    KEYSALTLIST(new KOptionInfo("-e", "key saltlist", KOptionType.STR)),
+    K(new KOptionInfo("-k", "keytab file path", KOptionType.STR)),
+    KEYTAB(new KOptionInfo("-keytab", "keytab file path", KOptionType.STR)),
+    CCACHE(new KOptionInfo("-c", "credentials cache", KOptionType.FILE));
 
-    private String name;
-    private KOptionGroup group;
-    private KOptionType type = KOptionType.NONE;
-    private String description;
-    private Object value;
+    private final KOptionInfo optionInfo;
 
-    KadminOption(String description) {
-        this(description, KOptionType.NOV);
+    KadminOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
     }
 
-    KadminOption(String description, KOptionType type) {
-        this.description = description;
-        this.type = type;
-    }
-
-    KadminOption(String name, String description) {
-        this(name, description, KOptionType.NOV);
-    }
-
-    KadminOption(String name, String description, KOptionType type) {
-        this.name = name;
-        this.description = description;
-        this.type = type;
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
     }
 
     public static KadminOption fromName(String name) {
         if (name != null) {
-            for (KadminOption kopt : values()) {
-                if (kopt.getName().equals(name)) {
-                    return (KadminOption) kopt;
+            for (KadminOption ko : values()) {
+                if (ko.name().equals(name)) {
+                    return ko;
                 }
             }
         }
         return NONE;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getOptionName() {
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionType getType() {
-        return this.type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setType(KOptionType type) {
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        if (name != null) {
-            return name;
+    public static KadminOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (KadminOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
         }
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return this.description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Object getValue() {
-        return value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setGroup(KOptionGroup group) {
-        this.group = group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionGroup getGroup() {
-        return group;
+        return NONE;
     }
 }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbKdcOption.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbKdcOption.java
new file mode 100644
index 0000000..cee1d23
--- /dev/null
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbKdcOption.java
@@ -0,0 +1,73 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.kerberos.kerb.client;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * This defines KDC options for client side API to use.
+ */
+public enum KrbKdcOption implements KOption {
+    NONE(null),
+
+    /* KDC flags */
+    FORWARDABLE(new KOptionInfo("forwardable", "forwardable",
+        KrbOptionGroup.KDC_FLAGS)),
+    PROXIABLE(new KOptionInfo("proxiable", "proxiable",
+        KrbOptionGroup.KDC_FLAGS)),
+    REQUEST_ANONYMOUS(new KOptionInfo("request-anonymous",
+        "request anonymous", KrbOptionGroup.KDC_FLAGS)),
+    VALIDATE(new KOptionInfo("validate", "validate",
+        KrbOptionGroup.KDC_FLAGS)),
+    RENEW(new KOptionInfo("renew", "renew",
+        KrbOptionGroup.KDC_FLAGS)),
+    RENEWABLE(new KOptionInfo("renewable", "renewable",
+        KrbOptionGroup.KDC_FLAGS)),
+    RENEWABLE_OK(new KOptionInfo("renewable-ok", "renewable ok",
+        KrbOptionGroup.KDC_FLAGS)),
+    CANONICALIZE(new KOptionInfo("canonicalize", "canonicalize",
+        KrbOptionGroup.KDC_FLAGS));
+
+    private final KOptionInfo optionInfo;
+
+    KrbKdcOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static KrbKdcOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (KrbKdcOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOption.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOption.java
index e31849b..06afec2 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOption.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOption.java
@@ -20,209 +20,79 @@
 package org.apache.kerby.kerberos.kerb.client;
 
 import org.apache.kerby.KOption;
-import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
 import org.apache.kerby.KOptionType;
 
 /**
  * This defines all the options that come across the client side.
  */
 public enum KrbOption implements KOption {
-    NONE("NONE", null),
-    CLIENT_PRINCIPAL("client-principal", "Client principal", KOptionType.STR),
-    KDC_REALM("kdc-realm", "kdc realm", KOptionType.STR),
-    KDC_HOST("kdc-host", "kdc host", KOptionType.STR),
-    KDC_TCP_PORT("kdc-tcp-port", "kdc tcp port", KOptionType.INT),
-    ALLOW_UDP("allow-udp", "allow udp", KOptionType.BOOL),
-    ALLOW_TCP("allow-tcp", "allow tcp", KOptionType.BOOL),
-    KDC_UDP_PORT("kdc-udp-port", "kdc udp port", KOptionType.INT),
-    CONN_TIMEOUT("conn-timeout", "connection timeout", KOptionType.INT),
-    LIFE_TIME("life-time", "life time", KOptionType.INT),
-    START_TIME("start-time", "start time", KOptionType.INT),
-    RENEWABLE_TIME("renewable_lifetime", "renewable lifetime", KOptionType.INT),
+    NONE(null),
 
-    /* KDC flags */
-    FORWARDABLE("forwardable", "forwardable", KrbOptionGroup.KDC_FLAGS),
-    PROXIABLE("proxiable", "proxiable", KrbOptionGroup.KDC_FLAGS),
-    ANONYMOUS("anonymous", "anonymous", KrbOptionGroup.KDC_FLAGS),
-    VALIDATE("validate", "validate", KrbOptionGroup.KDC_FLAGS),
-    RENEW("renew", "renew", KrbOptionGroup.KDC_FLAGS),
-    RENEWABLE("renewable", "renewable", KrbOptionGroup.KDC_FLAGS),
-    RENEWABLE_OK("renewable-ok", "renewable ok", KrbOptionGroup.KDC_FLAGS),
-    CANONICALIZE("canonicalize", "canonicalize", KrbOptionGroup.KDC_FLAGS),
+    KDC_REALM(new KOptionInfo("kdc-realm", "kdc realm",
+        KOptionType.STR)),
+    KDC_HOST(new KOptionInfo("kdc-host", "kdc host",
+        KOptionType.STR)),
+    KDC_TCP_PORT(new KOptionInfo("kdc-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)),
+    KDC_UDP_PORT(new KOptionInfo("kdc-udp-port", "kdc udp port",
+        KOptionType.INT)),
+    CONN_TIMEOUT(new KOptionInfo("conn-timeout", "connection timeout",
+        KOptionType.INT)),
 
-    INCLUDE_ADDRESSES("include_addresses", "include addresses"),
-    AS_ENTERPRISE_PN("as-enterprise-pn", "client is enterprise principal name"),
+    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("using-password", "using password"),
-    USER_PASSWD("user-passwd", "User plain password"),
+    USE_PASSWD(new KOptionInfo("using-password", "using password")),
+    USER_PASSWD(new KOptionInfo("user-passwd", "User plain password")),
 
-    USE_KEYTAB("use-keytab", "use keytab"),
-    USE_DFT_KEYTAB("use-dft-keytab", "use default client keytab (with -k)"),
-    KEYTAB_FILE("keytab-file", "filename of keytab to use", KOptionType.FILE),
+    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("krb5-cache", "K5 cache name", KOptionType.FILE),
-    SERVICE_PRINCIPAL("service-principal", "service principal", KOptionType.STR),
-    SERVER_PRINCIPAL("server-principal", "server principal", KOptionType.STR),
-    ARMOR_CACHE("armor-cache", "armor credential cache", KOptionType.STR),
+    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("server-principal", "server 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));
 
-    USE_PKINIT("use-pkinit", "using pkinit"),
-    PKINIT_X509_IDENTITY("x509-identities", "X509 user private key and cert",
-        KrbOptionGroup.PKINIT, KOptionType.STR),
-    PKINIT_X509_PRIVATE_KEY("x509-privatekey", "X509 user private key",
-        KrbOptionGroup.PKINIT, KOptionType.STR),
-    PKINIT_X509_CERTIFICATE("x509-cert", "X509 user certificate",
-        KrbOptionGroup.PKINIT, KOptionType.STR),
-    PKINIT_X509_ANCHORS("x509-anchors", "X509 anchors",
-        KrbOptionGroup.PKINIT,
-        KOptionType.STR),
-    PKINIT_USING_RSA("using-rsa-or-dh", "Using RSA or DH",
-        KrbOptionGroup.PKINIT),
-    USE_PKINIT_ANONYMOUS("use-pkinit-anonymous", "X509 anonymous",
-        KrbOptionGroup.PKINIT),
+    private final KOptionInfo optionInfo;
 
-    USE_TOKEN("use-id-token", "Using identity token", KrbOptionGroup.TOKEN),
-    TOKEN_USER_ID_TOKEN("user-id-token", "User identity token",
-        KrbOptionGroup.TOKEN, KOptionType.STR),
-    TOKEN_USER_AC_TOKEN("user-ac-token", "User access token",
-        KrbOptionGroup.TOKEN, KOptionType.STR),
-    USE_TGT("use-tgt", "use tgt to get service ticket", KOptionType.OBJ);
-
-    private String name;
-    private KOptionGroup group;
-    private KOptionType type;
-    private String description;
-    private Object value;
-
-    KrbOption(String name, String description) {
-        this(name, description, KOptionType.NOV);
+    KrbOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
     }
 
-    KrbOption(String name, String description, KOptionType type) {
-        this(name, description, null, type);
-    }
-
-    KrbOption(String name, String description, KrbOptionGroup group) {
-        this(name, description, group, KOptionType.NOV);
-    }
-
-    KrbOption(String name, String description,
-              KrbOptionGroup group, KOptionType type) {
-        this.name = name;
-        this.description = description;
-        this.group = group;
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public String getOptionName() {
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setType(KOptionType type) {
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionType getType() {
-        return this.type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        if (name != null) {
-            return name;
-        }
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return this.description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Object getValue() {
-        return value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setGroup(KOptionGroup group) {
-        this.group = group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionGroup getGroup() {
-        return group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    public static KrbOption fromName(String name) {
-        if (name != null) {
-            for (KrbOption ko : values()) {
-                if (ko.getName().equals(name)) {
-                    return (KrbOption) ko;
-                }
-            }
-        }
-        return NONE;
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
     }
 
     public static KrbOption fromOptionName(String optionName) {
         if (optionName != null) {
             for (KrbOption ko : values()) {
-                if (ko.getOptionName().equals(optionName)) {
-                    return (KrbOption) ko;
+                if (ko.optionInfo != null
+                    && ko.name().equals(optionName)) {
+                    return ko;
                 }
             }
         }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOptionGroup.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOptionGroup.java
index 0b2af67..6700a91 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOptionGroup.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbOptionGroup.java
@@ -22,14 +22,14 @@
 import org.apache.kerby.KOptionGroup;
 
 /**
- * This defines option groups to categorize the options defined in KrbOption.
+ * This defines option groups to categorize the options defined in client side.
  */
 public enum KrbOptionGroup implements KOptionGroup {
     NONE,
+    KRB,
     KDC_FLAGS,
     PKINIT,
-    TOKEN,
-    KINIT;
+    TOKEN;
 
     @Override
     public String getGroupName() {
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbPkinitClient.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbPkinitClient.java
index 2766f12..0f8b8b6 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbPkinitClient.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbPkinitClient.java
@@ -74,10 +74,10 @@
                                 String privateKey) throws KrbException {
         KOptions requestOptions = new KOptions();
         requestOptions.add(KrbOption.CLIENT_PRINCIPAL, principal);
-        requestOptions.add(KrbOption.USE_PKINIT);
-        requestOptions.add(KrbOption.PKINIT_USING_RSA);
-        requestOptions.add(KrbOption.PKINIT_X509_IDENTITY, certificate);
-        requestOptions.add(KrbOption.PKINIT_X509_PRIVATE_KEY, privateKey);
+        requestOptions.add(PkinitOption.USE_PKINIT);
+        requestOptions.add(PkinitOption.USING_RSA);
+        requestOptions.add(PkinitOption.X509_IDENTITY, certificate);
+        requestOptions.add(PkinitOption.X509_PRIVATE_KEY, privateKey);
         return requestTgt(requestOptions);
     }
 
@@ -88,9 +88,9 @@
      */
     public TgtTicket requestTgt(String anchors) throws KrbException {
         KOptions requestOptions = new KOptions();
-        requestOptions.add(KrbOption.USE_PKINIT_ANONYMOUS);
+        requestOptions.add(PkinitOption.USE_ANONYMOUS);
         requestOptions.add(KrbOption.CLIENT_PRINCIPAL, "WELLKNOWN/ANONYMOUS");
-        requestOptions.add(KrbOption.PKINIT_X509_ANCHORS, anchors);
+        requestOptions.add(PkinitOption.X509_ANCHORS, anchors);
         return requestTgt(requestOptions);
     }
 }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbTokenClient.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbTokenClient.java
index d3a3874..3582113 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbTokenClient.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbTokenClient.java
@@ -78,7 +78,7 @@
         }
 
         KOptions requestOptions = new KOptions();
-        requestOptions.add(KrbOption.TOKEN_USER_ID_TOKEN, token);
+        requestOptions.add(TokenOption.USER_ID_TOKEN, token);
         requestOptions.add(KrbOption.ARMOR_CACHE, armorCache);
         return requestTgt(requestOptions);
     }
@@ -98,7 +98,7 @@
         }
 
         KOptions requestOptions = new KOptions();
-        requestOptions.add(KrbOption.TOKEN_USER_AC_TOKEN, token);
+        requestOptions.add(TokenOption.USER_AC_TOKEN, token);
         requestOptions.add(KrbOption.ARMOR_CACHE, armorCache);
         requestOptions.add(KrbOption.SERVER_PRINCIPAL, serverPrincipal);
 
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/PkinitOption.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/PkinitOption.java
new file mode 100644
index 0000000..969dc03
--- /dev/null
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/PkinitOption.java
@@ -0,0 +1,63 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.kerberos.kerb.client;
+
+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 PkinitOption implements KOption {
+    NONE(null),
+    USE_PKINIT(new KOptionInfo("use-pkinit", "using pkinit")),
+    X509_IDENTITY(new KOptionInfo("x509-identities", "X509 user private key and cert",
+        KOptionType.STR)),
+    X509_PRIVATE_KEY(new KOptionInfo("x509-privatekey", "X509 user private key",
+        KOptionType.STR)),
+    X509_CERTIFICATE(new KOptionInfo("x509-cert", "X509 user certificate", KOptionType.STR)),
+    X509_ANCHORS(new KOptionInfo("x509-anchors", "X509 anchors", KOptionType.STR)),
+    USING_RSA(new KOptionInfo("using-rsa-or-dh", "Using RSA or DH")),
+    USE_ANONYMOUS(new KOptionInfo("use-pkinit-anonymous", "X509 anonymous"));
+
+    private final KOptionInfo optionInfo;
+
+    PkinitOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static PkinitOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (PkinitOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/TokenOption.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/TokenOption.java
new file mode 100644
index 0000000..9dabea1
--- /dev/null
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/TokenOption.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.client;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * This defines all the token options.
+ */
+public enum TokenOption implements KOption {
+    NONE(null),
+
+    USE_TOKEN(new KOptionInfo("use-id-token", "Using identity token")),
+    USER_ID_TOKEN(new KOptionInfo("user-id-token", "User identity token",
+        KOptionType.STR)),
+    USER_AC_TOKEN(new KOptionInfo("user-ac-token", "User access token",
+        KOptionType.STR));
+
+    private final KOptionInfo optionInfo;
+
+    TokenOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static TokenOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (TokenOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
index ac9e5ca..97e19da 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/impl/AbstractInternalKrbClient.java
@@ -25,6 +25,8 @@
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
 import org.apache.kerby.kerberos.kerb.client.KrbOption;
 import org.apache.kerby.kerberos.kerb.client.KrbSetting;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
 import org.apache.kerby.kerberos.kerb.client.request.AsRequest;
 import org.apache.kerby.kerberos.kerb.client.request.AsRequestWithCert;
 import org.apache.kerby.kerberos.kerb.client.request.AsRequestWithKeytab;
@@ -81,13 +83,13 @@
             asRequest = new AsRequestWithPasswd(context);
         } else if (requestOptions.contains(KrbOption.USE_KEYTAB)) {
             asRequest = new AsRequestWithKeytab(context);
-        } else if (requestOptions.contains(KrbOption.USE_PKINIT_ANONYMOUS)) {
+        } else if (requestOptions.contains(PkinitOption.USE_ANONYMOUS)) {
             asRequest = new AsRequestWithCert(context);
-        } else if (requestOptions.contains(KrbOption.USE_PKINIT)) {
+        } else if (requestOptions.contains(PkinitOption.USE_PKINIT)) {
             asRequest = new AsRequestWithCert(context);
-        } else if (requestOptions.contains(KrbOption.USE_TOKEN)) {
+        } else if (requestOptions.contains(TokenOption.USE_TOKEN)) {
             asRequest = new AsRequestWithToken(context);
-        } else if (requestOptions.contains(KrbOption.TOKEN_USER_ID_TOKEN)) {
+        } else if (requestOptions.contains(TokenOption.USER_ID_TOKEN)) {
             asRequest = new AsRequestWithToken(context);
         }
 
@@ -100,7 +102,7 @@
                     KrbOption.CLIENT_PRINCIPAL);
             principal = fixPrincipal(principal);
             PrincipalName principalName = new PrincipalName(principal);
-            if (requestOptions.contains(KrbOption.USE_PKINIT_ANONYMOUS)) {
+            if (requestOptions.contains(PkinitOption.USE_ANONYMOUS)) {
                 principalName.setNameType(NameType.NT_WELLKNOWN);
             }
             asRequest.setClientPrincipal(principalName);
@@ -112,7 +114,7 @@
             asRequest.setServerPrincipal(serverPrincipal);
         }
 
-        asRequest.setKrbOptions(requestOptions);
+        asRequest.setRequestOptions(requestOptions);
 
         return doRequestTgt(asRequest);
     }
@@ -123,11 +125,12 @@
     @Override
     public SgtTicket requestSgt(KOptions requestOptions) throws KrbException {
         TgsRequest tgsRequest = null;
-        if (requestOptions.contains(KrbOption.TOKEN_USER_AC_TOKEN)) {
+        if (requestOptions.contains(TokenOption.USER_AC_TOKEN)) {
             tgsRequest = new TgsRequestWithToken(context);
         } else if (requestOptions.contains(KrbOption.USE_TGT)) {
-            KOption tgt = requestOptions.getOption(KrbOption.USE_TGT);
-            tgsRequest = new TgsRequestWithTgt(context, (TgtTicket) tgt.getValue());
+            KOption kOpt = requestOptions.getOption(KrbOption.USE_TGT);
+            tgsRequest = new TgsRequestWithTgt(context,
+                (TgtTicket) kOpt.getOptionInfo().getValue());
         }
 
         if (tgsRequest == null) {
@@ -138,7 +141,7 @@
         String serverPrincipal = fixPrincipal(requestOptions.
                 getStringOption(KrbOption.SERVER_PRINCIPAL));
         tgsRequest.setServerPrincipal(new PrincipalName(serverPrincipal));
-        tgsRequest.setKrbOptions(requestOptions);
+        tgsRequest.setRequestOptions(requestOptions);
 
         return doRequestSgt(tgsRequest);
     }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/pkinit/PkinitPreauth.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/pkinit/PkinitPreauth.java
index 90b1572..f00cf0f 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/pkinit/PkinitPreauth.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/pkinit/PkinitPreauth.java
@@ -24,7 +24,7 @@
 import org.apache.kerby.asn1.type.Asn1ObjectIdentifier;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
 import org.apache.kerby.kerberos.kerb.client.preauth.AbstractPreauthPlugin;
 import org.apache.kerby.kerberos.kerb.client.request.KdcRequest;
 import org.apache.kerby.kerberos.kerb.common.CheckSumUtil;
@@ -100,13 +100,13 @@
     public void setPreauthOptions(KdcRequest kdcRequest,
                                   PluginRequestContext requestContext,
                                   KOptions options) {
-        if (options.contains(KrbOption.PKINIT_X509_IDENTITY)) {
+        if (options.contains(PkinitOption.X509_IDENTITY)) {
             pkinitContext.identityOpts.identity =
-                    options.getStringOption(KrbOption.PKINIT_X509_IDENTITY);
+                    options.getStringOption(PkinitOption.X509_IDENTITY);
         }
 
-        if (options.contains(KrbOption.PKINIT_X509_ANCHORS)) {
-            String anchorsString = options.getStringOption(KrbOption.PKINIT_X509_ANCHORS);
+        if (options.contains(PkinitOption.X509_ANCHORS)) {
+            String anchorsString = options.getStringOption(PkinitOption.X509_ANCHORS);
 
             List<String> anchors;
             if (anchorsString == null) {
@@ -117,9 +117,9 @@
             pkinitContext.identityOpts.anchors.addAll(anchors);
         }
 
-        if (options.contains(KrbOption.PKINIT_USING_RSA)) {
+        if (options.contains(PkinitOption.USING_RSA)) {
             pkinitContext.pluginOpts.usingRsa =
-                    options.getBooleanOption(KrbOption.PKINIT_USING_RSA, true);
+                    options.getBooleanOption(PkinitOption.USING_RSA, true);
         }
     }
 
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
index 274f645..c505e88 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/preauth/token/TokenPreauth.java
@@ -23,7 +23,7 @@
 import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
 import org.apache.kerby.kerberos.kerb.client.preauth.AbstractPreauthPlugin;
 import org.apache.kerby.kerberos.kerb.client.request.KdcRequest;
 import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
@@ -98,16 +98,16 @@
                                   PluginRequestContext requestContext,
                                   KOptions options) {
 
-        tokenContext.usingIdToken = options.getBooleanOption(KrbOption.USE_TOKEN, false);
+        tokenContext.usingIdToken = options.getBooleanOption(TokenOption.USE_TOKEN, false);
         if (tokenContext.usingIdToken) {
-            if (options.contains(KrbOption.TOKEN_USER_ID_TOKEN)) {
+            if (options.contains(TokenOption.USER_ID_TOKEN)) {
                 tokenContext.token =
-                        (AuthToken) options.getOptionValue(KrbOption.TOKEN_USER_ID_TOKEN);
+                        (AuthToken) options.getOptionValue(TokenOption.USER_ID_TOKEN);
             }
         } else {
-            if (options.contains(KrbOption.TOKEN_USER_AC_TOKEN)) {
+            if (options.contains(TokenOption.USER_AC_TOKEN)) {
                 tokenContext.token =
-                        (AuthToken) options.getOptionValue(KrbOption.TOKEN_USER_AC_TOKEN);
+                        (AuthToken) options.getOptionValue(TokenOption.USER_AC_TOKEN);
             }
         }
 
@@ -174,13 +174,13 @@
     private PaDataEntry makeEntry(KdcRequest kdcRequest) throws KrbException {
         KOptions options = kdcRequest.getPreauthOptions();
 
-        KOption idToken = options.getOption(KrbOption.TOKEN_USER_ID_TOKEN);
-        KOption acToken = options.getOption(KrbOption.TOKEN_USER_AC_TOKEN);
+        KOption idToken = options.getOption(TokenOption.USER_ID_TOKEN);
+        KOption acToken = options.getOption(TokenOption.USER_AC_TOKEN);
         AuthToken authToken;
         if (idToken != null) {
-            authToken = (AuthToken) idToken.getValue();
+            authToken = (AuthToken) idToken.getOptionInfo().getValue();
         } else if (acToken != null) {
-            authToken = (AuthToken) acToken.getValue();
+            authToken = (AuthToken) acToken.getOptionInfo().getValue();
         } else {
             throw new KrbException("missing token.");
         }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredRequest.java
index 9bb011b..e122856 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/ArmoredRequest.java
@@ -88,7 +88,7 @@
     public KOptions getPreauthOptions() {
         KOptions results = new KOptions();
 
-        KOptions krbOptions = kdcRequest.getKrbOptions();
+        KOptions krbOptions = kdcRequest.getRequestOptions();
         results.add(krbOptions.getOption(KrbOption.ARMOR_CACHE));
 
         return results;
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
index cb080be..7f35d87 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequest.java
@@ -23,7 +23,8 @@
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.ccache.CredentialCache;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
 import org.apache.kerby.kerberos.kerb.common.KrbUtil;
 import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
 import org.apache.kerby.kerberos.kerb.type.base.HostAddress;
@@ -90,9 +91,9 @@
         String clientRealm = getKdcRep().getCrealm();
         clientPrincipal.setRealm(clientRealm);
 
-        if (!(getKrbOptions().contains(KrbOption.USE_PKINIT_ANONYMOUS)
+        if (!(getRequestOptions().contains(PkinitOption.USE_ANONYMOUS)
                 && KrbUtil.pricipalCompareIgnoreRealm(clientPrincipal, getClientPrincipal()))
-                && !getKrbOptions().contains(KrbOption.TOKEN_USER_ID_TOKEN)
+                && !getRequestOptions().contains(TokenOption.USER_ID_TOKEN)
                 && !clientPrincipal.equals(getClientPrincipal())) {
             throw new KrbException(KrbErrorCode.KDC_ERR_CLIENT_NAME_MISMATCH);
         }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithCert.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithCert.java
index 19a02f8..88ee075 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithCert.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithCert.java
@@ -29,7 +29,7 @@
 import org.apache.kerby.kerberos.kerb.KrbErrorCode;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
 import org.apache.kerby.kerberos.kerb.common.KrbUtil;
 import org.apache.kerby.kerberos.kerb.crypto.dh.DhClient;
 import org.apache.kerby.kerberos.kerb.preauth.pkinit.CMSMessageType;
@@ -85,14 +85,14 @@
     public KOptions getPreauthOptions() {
         KOptions results = new KOptions();
 
-        KOptions krbOptions = getKrbOptions();
-        results.add(krbOptions.getOption(KrbOption.PKINIT_X509_CERTIFICATE));
-        results.add(krbOptions.getOption(KrbOption.PKINIT_X509_ANCHORS));
-        results.add(krbOptions.getOption(KrbOption.PKINIT_X509_PRIVATE_KEY));
-        results.add(krbOptions.getOption(KrbOption.PKINIT_X509_IDENTITY));
-        results.add(krbOptions.getOption(KrbOption.PKINIT_USING_RSA));
+        KOptions krbOptions = getRequestOptions();
+        results.add(krbOptions.getOption(PkinitOption.X509_CERTIFICATE));
+        results.add(krbOptions.getOption(PkinitOption.X509_ANCHORS));
+        results.add(krbOptions.getOption(PkinitOption.X509_PRIVATE_KEY));
+        results.add(krbOptions.getOption(PkinitOption.X509_IDENTITY));
+        results.add(krbOptions.getOption(PkinitOption.USING_RSA));
 
-        if (krbOptions.contains(KrbOption.USE_PKINIT_ANONYMOUS)) {
+        if (krbOptions.contains(PkinitOption.USE_ANONYMOUS)) {
             getKdcOptions().setFlag(KdcOption.REQUEST_ANONYMOUS);
         }
 
@@ -127,7 +127,8 @@
                 PkinitCrypto.verifyCMSSignedData(
                         CMSMessageType.CMS_SIGN_SERVER, signedData);
 
-                String anchorFileName = getPreauthOptions().getStringOption(KrbOption.PKINIT_X509_ANCHORS);
+                String anchorFileName =
+                    getPreauthOptions().getStringOption(PkinitOption.X509_ANCHORS);
 
                 X509Certificate x509Certificate = null;
                 try {
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithKeytab.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithKeytab.java
index c71d096..b6d1653 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithKeytab.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithKeytab.java
@@ -40,7 +40,7 @@
 
     private Keytab getKeytab() {
         File keytabFile = null;
-        KOptions kOptions = getKrbOptions();
+        KOptions kOptions = getRequestOptions();
 
         if (kOptions.contains(KrbOption.KEYTAB_FILE)) {
             keytabFile = kOptions.getFileOption(KrbOption.KEYTAB_FILE);
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithPasswd.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithPasswd.java
index 0d73193..df3a5a9 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithPasswd.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithPasswd.java
@@ -35,7 +35,7 @@
     }
 
     public String getPassword() {
-        return getKrbOptions().getStringOption(KrbOption.USER_PASSWD);
+        return getRequestOptions().getStringOption(KrbOption.USER_PASSWD);
     }
 
     @Override
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
index 5d127dc..32ca604 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/AsRequestWithToken.java
@@ -21,7 +21,7 @@
 
 import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
 import org.apache.kerby.kerberos.kerb.type.pa.PaDataType;
 
 /**
@@ -38,11 +38,11 @@
     @Override
     public KOptions getPreauthOptions() {
         KOptions results = super.getPreauthOptions();
-        KOptions krbOptions = getKrbOptions();
+        KOptions krbOptions = getRequestOptions();
 
-        results.add(krbOptions.getOption(KrbOption.USE_TOKEN));
-        results.add(krbOptions.getOption(KrbOption.TOKEN_USER_ID_TOKEN));
-        //results.add(krbOptions.getOption(KrbOption.TOKEN_USER_AC_TOKEN));
+        results.add(krbOptions.getOption(TokenOption.USE_TOKEN));
+        results.add(krbOptions.getOption(TokenOption.USER_ID_TOKEN));
+        //results.add(krbOptions.getOption(KrbOption.USER_AC_TOKEN));
 
         return results;
     }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/KdcRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/KdcRequest.java
index c2df62e..08ca20b 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/KdcRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/KdcRequest.java
@@ -23,6 +23,7 @@
 import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
+import org.apache.kerby.kerberos.kerb.client.KrbOption;
 import org.apache.kerby.kerberos.kerb.client.KrbOptionGroup;
 import org.apache.kerby.kerberos.kerb.client.preauth.KrbFastRequestState;
 import org.apache.kerby.kerberos.kerb.client.preauth.PreauthContext;
@@ -59,7 +60,7 @@
     protected Map<String, Object> credCache;
     private KrbContext context;
     private Object sessionData;
-    private KOptions krbOptions;
+    private KOptions requestOptions;
     private PrincipalName serverPrincipal;
     private List<HostAddress> hostAddresses = new ArrayList<HostAddress>();
     private KdcOptions kdcOptions = new KdcOptions();
@@ -111,12 +112,12 @@
         this.sessionData = sessionData;
     }
 
-    public KOptions getKrbOptions() {
-        return krbOptions;
+    public KOptions getRequestOptions() {
+        return requestOptions;
     }
 
-    public void setKrbOptions(KOptions options) {
-        this.krbOptions = options;
+    public void setRequestOptions(KOptions options) {
+        this.requestOptions = options;
     }
 
     public boolean isRetrying() {
@@ -409,10 +410,11 @@
         kdcOptions.setFlag(KdcOption.PROXIABLE);
         kdcOptions.setFlag(KdcOption.RENEWABLE_OK);
 
-        for (KOption kOpt: krbOptions.getOptions()) {
-            if (kOpt.getGroup() == KrbOptionGroup.KDC_FLAGS) {
-                KdcOption kdcOption = KdcOption.valueOf(kOpt.getOptionName());
-                boolean flagValue = krbOptions.getBooleanOption(kOpt, false);
+        for (KOption kOpt: requestOptions.getOptions()) {
+            if (kOpt.getOptionInfo().getGroup() == KrbOptionGroup.KDC_FLAGS) {
+                KrbOption krbOption = (KrbOption) kOpt;
+                KdcOption kdcOption = KdcOption.valueOf(krbOption.name());
+                boolean flagValue = requestOptions.getBooleanOption(kOpt, false);
                 kdcOptions.setFlag(kdcOption, flagValue);
             }
         }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
index dcc0d0d..cc4b3c6 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequest.java
@@ -58,7 +58,7 @@
 
     @Override
     public void process() throws KrbException {
-        String serverPrincipal = getKrbOptions().getStringOption(KrbOption.SERVER_PRINCIPAL);
+        String serverPrincipal = getRequestOptions().getStringOption(KrbOption.SERVER_PRINCIPAL);
         if (serverPrincipal == null) {
             LOG.warn("Server principal is null.");
         }
diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequestWithToken.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequestWithToken.java
index c27f622..b891f33 100644
--- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequestWithToken.java
+++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/request/TgsRequestWithToken.java
@@ -23,7 +23,7 @@
 import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbContext;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
 import org.apache.kerby.kerberos.kerb.type.base.AuthToken;
 import org.apache.kerby.kerberos.kerb.type.base.PrincipalName;
 import org.apache.kerby.kerberos.kerb.type.pa.PaDataType;
@@ -42,18 +42,18 @@
     @Override
     public KOptions getPreauthOptions() {
         KOptions results = super.getPreauthOptions();
-        KOptions krbOptions = getKrbOptions();
+        KOptions krbOptions = getRequestOptions();
 
-        results.add(krbOptions.getOption(KrbOption.USE_TOKEN));
-        results.add(krbOptions.getOption(KrbOption.TOKEN_USER_AC_TOKEN));
+        results.add(krbOptions.getOption(TokenOption.USE_TOKEN));
+        results.add(krbOptions.getOption(TokenOption.USER_AC_TOKEN));
 
         return results;
     }
 
     @Override
     public PrincipalName getClientPrincipal() {
-        KOption acToken = getPreauthOptions().getOption(KrbOption.TOKEN_USER_AC_TOKEN);
-        AuthToken authToken = (AuthToken) acToken.getValue();
+        KOption acToken = getPreauthOptions().getOption(TokenOption.USER_AC_TOKEN);
+        AuthToken authToken = (AuthToken) acToken.getOptionInfo().getValue();
         return new PrincipalName(authToken.getSubject());
     }
 }
diff --git a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/kdc/KdcOption.java b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/kdc/KdcOption.java
index 7e44c96..cb0dbcc 100644
--- a/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/kdc/KdcOption.java
+++ b/kerby-kerb/kerb-core/src/main/java/org/apache/kerby/kerberos/kerb/type/kdc/KdcOption.java
@@ -58,7 +58,7 @@
 
     private final int value;
 
-    private KdcOption(int value) {
+    KdcOption(int value) {
         this.value = value;
     }
 
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcServerOption.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcServerOption.java
index 5228285..9b808fa 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcServerOption.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/KdcServerOption.java
@@ -20,160 +20,33 @@
 package org.apache.kerby.kerberos.kerb.server;
 
 import org.apache.kerby.KOption;
-import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
 import org.apache.kerby.KOptionType;
 
 /**
  * KDC server startup options
  */
 public enum KdcServerOption implements KOption {
-    NONE("NONE"),
-    INNER_KDC_IMPL("inner KDC impl", KOptionType.OBJ),
-    KDC_REALM("kdc realm", KOptionType.STR),
-    KDC_HOST("kdc host", KOptionType.STR),
-    KDC_PORT("kdc port", KOptionType.INT),
-    ALLOW_TCP("allow tcp", KOptionType.BOOL),
-    KDC_TCP_PORT("kdc tcp port", KOptionType.INT),
-    ALLOW_UDP("allow udp", KOptionType.BOOL),
-    KDC_UDP_PORT("kdc udp port", KOptionType.INT),
-    WORK_DIR("work dir", KOptionType.DIR),
-    ENABLE_DEBUG("enable debug", KOptionType.BOOL);
+    NONE(null),
+    INNER_KDC_IMPL(new KOptionInfo("inner KDC impl", "inner KDC impl", KOptionType.OBJ)),
+    KDC_REALM(new KOptionInfo("kdc realm", "kdc realm", KOptionType.STR)),
+    KDC_HOST(new KOptionInfo("kdc host", "kdc host", KOptionType.STR)),
+    KDC_PORT(new KOptionInfo("kdc port", "kdc port", KOptionType.INT)),
+    ALLOW_TCP(new KOptionInfo("allow tcp", "allow tcp", KOptionType.BOOL)),
+    KDC_TCP_PORT(new KOptionInfo("kdc tcp port", "kdc tcp port", KOptionType.INT)),
+    ALLOW_UDP(new KOptionInfo("allow udp", "allow udp", KOptionType.BOOL)),
+    KDC_UDP_PORT(new KOptionInfo("kdc udp port", "kdc udp port", KOptionType.INT)),
+    WORK_DIR(new KOptionInfo("work dir", "work dir", KOptionType.DIR)),
+    ENABLE_DEBUG(new KOptionInfo("enable debug", "enable debug", KOptionType.BOOL));
 
-    private String name;
-    private KOptionGroup group;
-    private KOptionType type;
-    private String description;
-    private Object value;
+    private final KOptionInfo optionInfo;
 
-    KdcServerOption(String description) {
-        this(description, KOptionType.NOV); // As a flag by default
+    KdcServerOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
     }
 
-    KdcServerOption(String description, KOptionType type) {
-        this.description = description;
-        this.type = type;
-    }
-
-    KdcServerOption(String name, String description) {
-        this(name, description, KOptionType.NOV); // As a flag by default
-    }
-
-    KdcServerOption(String name, String description, KOptionType type) {
-        this.name = name;
-        this.description = description;
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public String getOptionName() {
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setType(KOptionType type) {
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionType getType() {
-        return this.type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        if (name != null) {
-            return name;
-        }
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return this.description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Object getValue() {
-        return value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setGroup(KOptionGroup group) {
-        this.group = group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionGroup getGroup() {
-        return group;
-    }
-
-    public static KdcServerOption fromName(String name) {
-        if (name != null) {
-            for (KdcServerOption ko : values()) {
-                if (ko.getName().equals(name)) {
-                    return (KdcServerOption) ko;
-                }
-            }
-        }
-        return NONE;
-    }
-
-    public static KdcServerOption fromOptionName(String optionName) {
-        if (optionName != null) {
-            for (KdcServerOption ko : values()) {
-                if (ko.getOptionName().equals(optionName)) {
-                    return (KdcServerOption) ko;
-                }
-            }
-        }
-        return NONE;
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
     }
 }
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/ToolUtil.java b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/ToolUtil.java
deleted file mode 100644
index 91f8aef..0000000
--- a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/ToolUtil.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- *
- */
-package org.apache.kerby.kerberos.tool;
-
-import org.apache.kerby.KOption;
-import org.apache.kerby.KOptions;
-import org.apache.kerby.kerberos.kerb.client.KrbOption;
-
-/**
- * Tool utilities.
- */
-public class ToolUtil {
-
-    /**
-     * Convert tool (like kinit) options to KrbOptions.
-     * @param toolOptions krb options
-     * @return krb options
-     */
-    public static KOptions convertOptions(KOptions toolOptions) {
-        KOptions results = new KOptions();
-
-        for (KOption toolOpt : toolOptions.getOptions()) {
-            KrbOption krbOpt = KrbOption.fromOptionName(toolOpt.getOptionName());
-            if (krbOpt != KrbOption.NONE) {
-                krbOpt.setValue(toolOpt.getValue());
-                results.add(krbOpt);
-            }
-        }
-
-        return results;
-    }
-}
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitOption.java b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitOption.java
index ad5d23d..00e377f 100644
--- a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitOption.java
+++ b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitOption.java
@@ -20,161 +20,81 @@
 package org.apache.kerby.kerberos.tool.kinit;
 
 import org.apache.kerby.KOption;
-import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
 import org.apache.kerby.KOptionType;
+import org.apache.kerby.kerberos.kerb.client.KrbOptionGroup;
 
 public enum KinitOption implements KOption {
-    NONE("NONE"),
-    CLIENT_PRINCIPAL("client-principal", "Client principal", KOptionType.STR),
-    LIFE_TIME("-l", "lifetime", KOptionType.INT),
-    START_TIME("-s", "start time", KOptionType.INT),
-    RENEWABLE_LIFE("-r", "renewable lifetime", KOptionType.INT),
-    FORWARDABLE("-f", "forwardable"),
-    NOT_FORWARDABLE("-F", "not forwardable"),
-    PROXIABLE("-p", "proxiable"),
-    NOT_PROXIABLE("-P", "not proxiable"),
-    ANONYMOUS("-n", "anonymous"),
-    INCLUDE_ADDRESSES("-a", "include addresses"),
-    NOT_INCLUDE_ADDRESSES("-A", "do not include addresses"),
-    VALIDATE("-v", "validate"),
-    RENEW("-R", "renew"),
-    CANONICALIZE("-C", "canonicalize"),
-    AS_ENTERPRISE_PN("-E", "client is enterprise principal name"),
-    USE_PASSWD("using password", "using password"),
-    USER_PASSWD("user-passwd", "User plain password"),
-    USE_KEYTAB("-k", "use keytab"),
-    USE_DFT_KEYTAB("-i", "use default client keytab (with -k)"),
-    KEYTAB_FILE("-t", "filename of keytab to use", KOptionType.FILE),
-    KRB5_CACHE("-c", "Kerberos 5 cache name", KOptionType.STR),
-    SERVICE("-S", "service", KOptionType.STR),
-    ARMOR_CACHE("-T", "armor credential cache", KOptionType.FILE),
-    XATTR("-X", "<attribute>[=<value>]", KOptionType.STR),
-    CONF_DIR("-conf", "conf dir", KOptionType.DIR);
+    NONE(null),
 
-    private String name;
-    private KOptionGroup group;
-    private KOptionType type = KOptionType.NONE;
-    private String description;
-    private Object value;
+    CLIENT_PRINCIPAL(new KOptionInfo("client-principal", "Client principal",
+        KrbOptionGroup.KRB, KOptionType.STR)),
+    LIFE_TIME(new KOptionInfo("-l", "lifetime",
+        KrbOptionGroup.KRB, KOptionType.INT)),
+    START_TIME(new KOptionInfo("-s", "start time",
+        KrbOptionGroup.KRB, KOptionType.INT)),
+    RENEWABLE_LIFE(new KOptionInfo("-r", "renewable lifetime",
+        KrbOptionGroup.KRB, KOptionType.INT)),
+    AS_ENTERPRISE_PN(new KOptionInfo("-E", "client is enterprise principal name",
+        KrbOptionGroup.KRB)),
+    INCLUDE_ADDRESSES(new KOptionInfo("-a", "include addresses",
+        KrbOptionGroup.KRB)),
+    NOT_INCLUDE_ADDRESSES(new KOptionInfo("-A", "do not include addresses",
+        KrbOptionGroup.KRB)),
 
-    KinitOption(String description) {
-        this(description, KOptionType.NOV); // As a flag by default
+    FORWARDABLE(new KOptionInfo("-f", "forwardable",
+        KrbOptionGroup.KDC_FLAGS)),
+    NOT_FORWARDABLE(new KOptionInfo("-F", "not forwardable",
+        KrbOptionGroup.KDC_FLAGS)),
+    PROXIABLE(new KOptionInfo("-p", "proxiable",
+        KrbOptionGroup.KDC_FLAGS)),
+    NOT_PROXIABLE(new KOptionInfo("-P", "not proxiable",
+        KrbOptionGroup.KDC_FLAGS)),
+    ANONYMOUS(new KOptionInfo("-n", "anonymous",
+        KrbOptionGroup.KDC_FLAGS)),
+    VALIDATE(new KOptionInfo("-v", "validate",
+        KrbOptionGroup.KDC_FLAGS)),
+    RENEW(new KOptionInfo("-R", "renew",
+        KrbOptionGroup.KDC_FLAGS)),
+    CANONICALIZE(new KOptionInfo("-C", "canonicalize",
+        KrbOptionGroup.KDC_FLAGS)),
+
+    USE_PASSWD(new KOptionInfo("using password", "using password",
+        KrbOptionGroup.KRB)),
+    USER_PASSWD(new KOptionInfo("user-passwd", "User plain password",
+        KrbOptionGroup.KRB)),
+    USE_KEYTAB(new KOptionInfo("-k", "use keytab",
+        KrbOptionGroup.KRB)),
+    USE_DFT_KEYTAB(new KOptionInfo("-i", "use default client keytab (with -k)",
+        KrbOptionGroup.KRB)),
+    KEYTAB_FILE(new KOptionInfo("-t", "filename of keytab to use",
+        KrbOptionGroup.KRB, KOptionType.FILE)),
+    KRB5_CACHE(new KOptionInfo("-c", "Kerberos 5 cache name",
+        KrbOptionGroup.KRB, KOptionType.STR)),
+    SERVICE(new KOptionInfo("-S", "service",
+        KrbOptionGroup.KRB, KOptionType.STR)),
+    ARMOR_CACHE(new KOptionInfo("-T", "armor credential cache",
+        KrbOptionGroup.KRB, KOptionType.FILE)),
+
+    XATTR(new KOptionInfo("-X", "<attribute>[=<value>]", KOptionType.STR)),
+    CONF_DIR(new KOptionInfo("-conf", "conf dir", KOptionType.DIR));
+
+    private final KOptionInfo optionInfo;
+
+    KinitOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
     }
 
-    KinitOption(String description, KOptionType type) {
-        this.description = description;
-        this.type = type;
-    }
-
-    KinitOption(String name, String description) {
-        this(name, description, KOptionType.NOV); // As a flag by default
-    }
-
-    KinitOption(String name, String description, KOptionType type) {
-        this.name = name;
-        this.description = description;
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
-    public String getOptionName() {
-        return name();
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setType(KOptionType type) {
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionType getType() {
-        return this.type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        if (name != null) {
-            return name;
-        }
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return this.description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Object getValue() {
-        return value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setGroup(KOptionGroup group) {
-        this.group = group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionGroup getGroup() {
-        return group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
     public static KinitOption fromName(String name) {
         if (name != null) {
             for (KinitOption ko : values()) {
-                if (ko.getName().equals(name)) {
-                    return (KinitOption) ko;
+                if (ko.name().equals(name)) {
+                    return ko;
                 }
             }
         }
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
index 05063c6..d09515f 100644
--- a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
+++ b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitTool.java
@@ -19,14 +19,19 @@
  */
 package org.apache.kerby.kerberos.tool.kinit;
 
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionGroup;
 import org.apache.kerby.KOptionType;
 import org.apache.kerby.KOptions;
 import org.apache.kerby.kerberos.kerb.KrbException;
 import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbKdcOption;
 import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.KrbOptionGroup;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
 import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
 import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
-import org.apache.kerby.kerberos.tool.ToolUtil;
 import org.apache.kerby.util.OSUtil;
 import org.apache.kerby.util.SysUtil;
 
@@ -113,8 +118,8 @@
         }
 
         if (ktOptions.contains(KinitOption.ANONYMOUS)) {
-            ktOptions.add(KrbOption.USE_PKINIT_ANONYMOUS);
-            ktOptions.add(KrbOption.PKINIT_X509_ANCHORS);
+            ktOptions.add(PkinitOption.USE_ANONYMOUS);
+            ktOptions.add(PkinitOption.X509_ANCHORS);
         } else if (!ktOptions.contains(KinitOption.USE_KEYTAB)) {
             //If not request tickets by keytab than by password.
             ktOptions.add(KinitOption.USE_PASSWD);
@@ -132,8 +137,7 @@
 
         TgtTicket tgt = null;
         try {
-            tgt = krbClient.requestTgt(
-                ToolUtil.convertOptions(ktOptions));
+            tgt = krbClient.requestTgt(convertOptions(ktOptions));
         } catch (KrbException e) {
             System.err.println("Authentication failed: " + e.getMessage());
             System.exit(1);
@@ -157,7 +161,7 @@
         }
 
         System.out.println("Successfully requested and stored ticket in "
-                + ccacheFile.getAbsolutePath());
+            + ccacheFile.getAbsolutePath());
         if (ktOptions.contains(KinitOption.SERVICE)) {
             String servicePrincipal = ktOptions.getStringOption(KinitOption.SERVICE);
             SgtTicket sgtTicket =
@@ -210,13 +214,14 @@
                 kto = KinitOption.NONE;
             }
 
-            if (kto.getType() != KOptionType.NOV) { // require a parameter
+            if (kto.getOptionInfo().getType() != KOptionType.NOV) {
+                // require a parameter
                 param = null;
                 if (i < args.length) {
                     param = args[i++];
                 }
                 if (param != null) {
-                    KOptions.parseSetValue(kto, param);
+                    KOptions.parseSetValue(kto.getOptionInfo(), param);
                 } else {
                     error = "Option " + opt + " require a parameter";
                 }
@@ -240,4 +245,34 @@
         System.exit(0);
     }
 
+    /**
+     * Convert kinit tool options to KOptions.
+     * @param toolOptions
+     * @return KOptions
+     */
+    static KOptions convertOptions(KOptions toolOptions) {
+        KOptions results = new KOptions();
+
+        for (KOption toolOpt : toolOptions.getOptions()) {
+            KinitOption kinitOption = (KinitOption) toolOpt;
+            KOptionGroup group = kinitOption.getOptionInfo().getGroup();
+            KOption kOpt = null;
+
+            if (group == KrbOptionGroup.KRB) {
+                kOpt = KrbOption.fromOptionName(kinitOption.name());
+            } else if (group == KrbOptionGroup.PKINIT) {
+                kOpt = PkinitOption.fromOptionName(kinitOption.name());
+            } else if (group == KrbOptionGroup.TOKEN) {
+                kOpt = TokenOption.fromOptionName(kinitOption.name());
+            } else if (group == KrbOptionGroup.KDC_FLAGS) {
+                kOpt = KrbKdcOption.fromOptionName(kinitOption.name());
+            }
+            if (kOpt != null && kOpt != KrbOption.NONE) {
+                kOpt.getOptionInfo().setValue(toolOpt.getOptionInfo().getValue());
+                results.add(kOpt);
+            }
+        }
+
+        return results;
+    }
 }
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistOption.java b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistOption.java
index b09fbf2..7382387 100644
--- a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistOption.java
+++ b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistOption.java
@@ -20,150 +20,46 @@
 package org.apache.kerby.kerberos.tool.klist;
 
 import org.apache.kerby.KOption;
-import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
 import org.apache.kerby.KOptionType;
 
 public enum KlistOption implements KOption {
-    NONE("NONE"),
-    CREDENTIALS_CACHE("-c", "specifies path of credentials cache", KOptionType.STR),
-    KEYTAB("-k", "specifies keytab"),
-    DEFAULT_CLIENT_KEYTAB("-i", "uses default client keytab if no name given"),
-    LIST_CREDENTIAL_CACHES("-l", "list credential caches in collection"),
-    ALL_CREDENTIAL_CACHES("-A", "shows content of all credential caches"),
-    ENCRYPTION_TYPE("-e", "shows encryption type"),
-    KERBEROS_VERSION("-V", "shows Kerberos version"),
-    AUTHORIZATION_DATA_TYPE("-d", "shows the submitted authorization data type"),
-    CREDENTIALS_FLAGS("-f", "show credential flags"),
-    EXIT_TGT_EXISTENCE("-s", "sets exit status based on valid tgt existence"),
-    DISPL_ADDRESS_LIST("-a", "displays the address list"),
-    NO_REVERSE_RESOLVE("-n", "do not reverse resolve"),
-    SHOW_KTAB_ENTRY_TS("-t", "shows keytab entry timestamps"),
-    SHOW_KTAB_ENTRY_KEY("-K", "show keytab entry keys");
+    NONE(null),
+    CREDENTIALS_CACHE(new KOptionInfo("-c", "specifies path of credentials cache",
+        KOptionType.STR)),
+    KEYTAB(new KOptionInfo("-k", "specifies keytab")),
+    DEFAULT_CLIENT_KEYTAB(new KOptionInfo("-i", "uses default client keytab if no name given")),
+    LIST_CREDENTIAL_CACHES(new KOptionInfo("-l", "list credential caches in collection")),
+    ALL_CREDENTIAL_CACHES(new KOptionInfo("-A", "shows content of all credential caches")),
+    ENCRYPTION_TYPE(new KOptionInfo("-e", "shows encryption type")),
+    KERBEROS_VERSION(new KOptionInfo("-V", "shows Kerberos version")),
+    AUTHORIZATION_DATA_TYPE(new KOptionInfo("-d", "shows the submitted authorization data type")),
+    CREDENTIALS_FLAGS(new KOptionInfo("-f", "show credential flags")),
+    EXIT_TGT_EXISTENCE(new KOptionInfo("-s", "sets exit status based on valid tgt existence")),
+    DISPL_ADDRESS_LIST(new KOptionInfo("-a", "displays the address list")),
+    NO_REVERSE_RESOLVE(new KOptionInfo("-n", "do not reverse resolve")),
+    SHOW_KTAB_ENTRY_TS(new KOptionInfo("-t", "shows keytab entry timestamps")),
+    SHOW_KTAB_ENTRY_KEY(new KOptionInfo("-K", "show keytab entry keys"));
 
-    private String name;
-    private KOptionGroup group;
-    private KOptionType type = KOptionType.NONE;
-    private String description;
-    private Object value;
+    private final KOptionInfo optionInfo;
 
-    KlistOption(String description) {
-        this(description, KOptionType.NOV);
+    KlistOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
     }
 
-    KlistOption(String description, KOptionType type) {
-        this.description = description;
-        this.type = type;
-    }
-
-    KlistOption(String name, String description) {
-        this(name, description, KOptionType.NOV);
-    }
-
-    KlistOption(String name, String description, KOptionType type) {
-        this.name = name;
-        this.description = description;
-        this.type = type;
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
     }
 
     public static KlistOption fromName(String name) {
         if (name != null) {
-            for (KlistOption klopt : values()) {
-                if (klopt.getName().equals(name)) {
-                    return (KlistOption) klopt;
+            for (KlistOption ko : values()) {
+                if (ko.name().equals(name)) {
+                    return ko;
                 }
             }
         }
         return NONE;
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getOptionName() {
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionType getType() {
-        return this.type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setType(KOptionType type) {
-        this.type = type;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getName() {
-        if (name != null) {
-            return name;
-        }
-        return name();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String getDescription() {
-        return this.description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setDescription(String description) {
-        this.description = description;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Object getValue() {
-        return value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setValue(Object value) {
-        this.value = value;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void setGroup(KOptionGroup group) {
-        this.group = group;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public KOptionGroup getGroup() {
-        return group;
-    }
 }
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistTool.java b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistTool.java
index 57dfe4b6..41b251e 100644
--- a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistTool.java
+++ b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/klist/KlistTool.java
@@ -211,13 +211,14 @@
                 break;
             }
 
-            if (error == null && klopt.getType() != KOptionType.NOV) { //needs value for this parameter
+            if (error == null && klopt.getOptionInfo().getType() != KOptionType.NOV) {
+                //needs value for this parameter
                 value = null;
                 if (i < args.length) {
                     value = args[i++];
                 }
                 if (value != null) {
-                    KOptions.parseSetValue(klopt, value);
+                    KOptions.parseSetValue(klopt.getOptionInfo(), value);
                 } else {
                     error = "Option" + klopt + "requires a following value";
                 }
@@ -228,7 +229,8 @@
             }
 
             klOptions.add(klopt);
-            if (klOptions.contains(KlistOption.KEYTAB) && klOptions.contains(KlistOption.CREDENTIALS_CACHE)) {
+            if (klOptions.contains(KlistOption.KEYTAB)
+                && klOptions.contains(KlistOption.CREDENTIALS_CACHE)) {
                 error = "Can not use '-c' and '-k' at the same time ";
                 printUsage(error);
             }
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java
index 873b4c9..76aa5c6 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/ToolUtil.java
@@ -56,13 +56,14 @@
                 error = "Invalid parameter:" + opt + " , it does not belong to any option.";
             }
 
-            if (kOption.getType() != KOptionType.NOV) { // require a parameter
+            if (kOption.getOptionInfo().getType() != KOptionType.NOV) {
+                // require a parameter
                 param = null;
                 if (i <= endIndex) {
                     param = commands[i++];
                 }
                 if (param != null) {
-                    kOptions.parseSetValue(kOption, param);
+                    kOptions.parseSetValue(kOption.getOptionInfo(), param);
                 } else {
                     error = "Option " + opt + " require a parameter";
                 }
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java
index 7ff18ac..5d15e28 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/ModifyPrincipalCommand.java
@@ -80,13 +80,14 @@
                 kOption = KadminOption.NONE;
             }
 
-            if (kOption.getType() != KOptionType.NOV) { // require a parameter
+            if (kOption.getOptionInfo().getType() != KOptionType.NOV) {
+                // require a parameter
                 param = null;
                 if (i < commands.length) {
                     param = commands[i++];
                 }
                 if (param != null) {
-                    KOptions.parseSetValue(kOption, param);
+                    KOptions.parseSetValue(kOption.getOptionInfo(), param);
                 } else {
                     error = "Option " + opt + " require a parameter";
                 }
diff --git a/kerby-util/src/main/java/org/apache/kerby/KOption.java b/kerby-util/src/main/java/org/apache/kerby/KOption.java
index c458232..4a3b189 100644
--- a/kerby-util/src/main/java/org/apache/kerby/KOption.java
+++ b/kerby-util/src/main/java/org/apache/kerby/KOption.java
@@ -22,85 +22,8 @@
 public interface KOption {
 
     /**
-     * Set koption type.
-     *
-     * @param type The type
+     * @return option info object
      */
-    void setType(KOptionType type);
-
-    /**
-     * Get koption type.
-     *
-     * @return The koption type
-     */
-    KOptionType getType();
-
-    /**
-     * Get option name.
-     *
-     * @return The koption name
-     */
-    String getOptionName();
-
-
-    /**
-     * Set name.
-     *
-     * @param name The name
-     */
-    void setName(String name);
-
-    /**
-     * Get name.
-     *
-     * @return The name
-     */
-    String getName();
-
-
-    /**
-     * Set description.
-     *
-     * @param description The description
-     */
-    void setDescription(String description);
-
-    /**
-     * Get description.
-     *
-     * @return The description
-     */
-    String getDescription();
-
-
-    /**
-     * Set value.
-     *
-     * @param value The value
-     */
-    void setValue(Object value);
-
-
-    /**
-     * Get value.
-     *
-     * @return The value
-     */
-    Object getValue();
-
-    /**
-     * Set group.
-     *
-     * @param value The group
-     */
-    void setGroup(KOptionGroup value);
-
-
-    /**
-     * Get group.
-     *
-     * @return The group
-     */
-    KOptionGroup getGroup();
+    KOptionInfo getOptionInfo();
 }
 
diff --git a/kerby-util/src/main/java/org/apache/kerby/KOptionInfo.java b/kerby-util/src/main/java/org/apache/kerby/KOptionInfo.java
new file mode 100644
index 0000000..071516e
--- /dev/null
+++ b/kerby-util/src/main/java/org/apache/kerby/KOptionInfo.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;
+
+public class KOptionInfo {
+    private String name;
+    private KOptionGroup group;
+    private KOptionType type;
+    private String description;
+    private Object value;
+
+    public KOptionInfo(String name, String description) {
+        this(name, description, KOptionType.NOV);
+    }
+
+    public KOptionInfo(String name, String description, KOptionType type) {
+        this(name, description, null, type);
+    }
+
+    public KOptionInfo(String name, String description, KOptionGroup group) {
+        this(name, description, group, KOptionType.NOV);
+    }
+
+    public KOptionInfo(String name, String description,
+              KOptionGroup group, KOptionType type) {
+        this.name = name;
+        this.description = description;
+        this.group = group;
+        this.type = type;
+    }
+
+    /**
+     * Set koption type.
+     *
+     * @param type The type
+     */
+    public void setType(KOptionType type) {
+        this.type = type;
+    }
+
+    /**
+     * Get koption type.
+     *
+     * @return The koption type
+     */
+    public KOptionType getType() {
+        return type;
+    }
+
+    /**
+     * Set name.
+     *
+     * @param name The name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get name.
+     *
+     * @return The name
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Set description.
+     *
+     * @param description The description
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * Get description.
+     *
+     * @return The description
+     */
+    public String getDescription() {
+        return description;
+    }
+
+
+    /**
+     * Set value.
+     *
+     * @param value The value
+     */
+    public void setValue(Object value) {
+        this.value = value;
+    }
+
+
+    /**
+     * Get value.
+     *
+     * @return The value
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Set group.
+     *
+     * @param group The group
+     */
+    public void setGroup(KOptionGroup group) {
+        this.group = group;
+    }
+
+    /**
+     * Get group.
+     *
+     * @return The group
+     */
+    public KOptionGroup getGroup() {
+        return group;
+    }
+}
+
diff --git a/kerby-util/src/main/java/org/apache/kerby/KOptions.java b/kerby-util/src/main/java/org/apache/kerby/KOptions.java
index 4ea1103..9934751 100644
--- a/kerby-util/src/main/java/org/apache/kerby/KOptions.java
+++ b/kerby-util/src/main/java/org/apache/kerby/KOptions.java
@@ -34,8 +34,7 @@
  */
 public class KOptions {
 
-    private final Map<KOption, KOption> options =
-            new HashMap<KOption, KOption>();
+    private final Map<KOption, KOption> options = new HashMap<>();
 
     /**
      * Parse string value according to kopt type.
@@ -43,7 +42,7 @@
      * @param strValue The string value
      * @return true when successful, false otherwise
      */
-    public static boolean parseSetValue(KOption kopt, String strValue) {
+    public static boolean parseSetValue(KOptionInfo kopt, String strValue) {
         KOptionType kt = kopt.getType();
         if (kt == KOptionType.NOV) {
             return true; // no need of a value
@@ -95,7 +94,7 @@
 
     public void add(KOption option, Object optionValue) {
         if (option != null) {
-            option.setValue(optionValue);
+            option.getOptionInfo().setValue(optionValue);
             add(option);
         }
     }
@@ -120,7 +119,7 @@
         if (!contains(option)) {
             return null;
         }
-        return options.get(option).getValue();
+        return options.get(option).getOptionInfo().getValue();
     }
 
     public String getStringOption(KOption option) {