You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by dr...@apache.org on 2015/04/24 01:56:20 UTC

directory-kerby git commit: Refactored KDC request handling related to ticket issuing

Repository: directory-kerby
Updated Branches:
  refs/heads/master 0bb77a111 -> 6de5ada93


Refactored KDC request handling related to ticket issuing


Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/6de5ada9
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/6de5ada9
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/6de5ada9

Branch: refs/heads/master
Commit: 6de5ada9389fbe7919a5af36dec91d50a058d7f4
Parents: 0bb77a1
Author: Drankye <dr...@gmail.com>
Authored: Fri Apr 24 07:55:58 2015 +0800
Committer: Drankye <dr...@gmail.com>
Committed: Fri Apr 24 07:55:58 2015 +0800

----------------------------------------------------------------------
 .../kerb/server/impl/DefaultKdcHandler.java     |   3 +-
 .../kerberos/kerb/server/request/AsRequest.java |  11 +-
 .../kerb/server/request/KdcRequest.java         | 171 +-------------
 .../server/request/ServiceTickertIssuer.java    |  50 ++++
 .../kerb/server/request/TgsRequest.java         |  21 +-
 .../kerb/server/request/TgtTickertIssuer.java   |  43 ++++
 .../kerb/server/request/TickertIssuer.java      | 231 +++++++++++++++++++
 7 files changed, 356 insertions(+), 174 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/impl/DefaultKdcHandler.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/impl/DefaultKdcHandler.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/impl/DefaultKdcHandler.java
index 96809ee..3ff9a10 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/impl/DefaultKdcHandler.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/impl/DefaultKdcHandler.java
@@ -67,7 +67,8 @@ public class DefaultKdcHandler extends KdcHandler implements Runnable {
             ByteBuffer krbResponse = handleMessage(message, isTcp, clientAddress);
             transport.sendMessage(krbResponse);
         } catch (Exception e) {
-            logger.debug("Error occured while processing request:", e);
+            e.printStackTrace();
+            logger.error("Error occured while processing request:", e);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
index 097a630..c402926 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/AsRequest.java
@@ -42,7 +42,7 @@ public class AsRequest extends KdcRequest {
         PrincipalName clientPrincipal = request.getReqBody().getCname();
         String clientRealm = request.getReqBody().getRealm();
         if (clientRealm == null || clientRealm.isEmpty()) {
-            clientRealm = kdcContext.getKdcRealm();
+            clientRealm = getKdcContext().getKdcRealm();
         }
         clientPrincipal.setRealm(clientRealm);
 
@@ -59,13 +59,20 @@ public class AsRequest extends KdcRequest {
     }
 
     @Override
+    protected void issueTicket() throws KrbException {
+        TickertIssuer issuer = new TgtTickertIssuer(this);
+        Ticket newTicket = issuer.issueTicket();
+        setTicket(newTicket);
+    }
+
+    @Override
     protected void makeReply() throws KrbException {
         Ticket ticket = getTicket();
 
         AsRep reply = new AsRep();
 
         reply.setCname(getClientEntry().getPrincipal());
-        reply.setCrealm(kdcContext.getKdcRealm());
+        reply.setCrealm(getKdcContext().getKdcRealm());
         reply.setTicket(ticket);
 
         EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
index 6430d3d..8ceaf6a 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/KdcRequest.java
@@ -19,32 +19,20 @@
  */
 package org.apache.kerby.kerberos.kerb.server.request;
 
-import org.apache.kerby.kerberos.kerb.KrbErrorCode;
-import org.apache.kerby.kerberos.kerb.KrbCodec;
+import org.apache.kerby.kerberos.kerb.*;
 import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
-import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
 import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
-import org.apache.kerby.kerberos.kerb.server.KdcConfig;
 import org.apache.kerby.kerberos.kerb.server.KdcContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.KdcFastContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.PreauthContext;
 import org.apache.kerby.kerberos.kerb.server.preauth.PreauthHandler;
-import org.apache.kerby.kerberos.kerb.KrbConstant;
-import org.apache.kerby.kerberos.kerb.KrbErrorException;
-import org.apache.kerby.kerberos.kerb.KrbException;
-import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
 import org.apache.kerby.kerberos.kerb.spec.base.*;
-import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOption;
-import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOptions;
 import org.apache.kerby.kerberos.kerb.spec.kdc.KdcRep;
 import org.apache.kerby.kerberos.kerb.spec.kdc.KdcReq;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaData;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataEntry;
 import org.apache.kerby.kerberos.kerb.spec.pa.PaDataType;
-import org.apache.kerby.kerberos.kerb.spec.ticket.EncTicketPart;
 import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
-import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlag;
-import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
 
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
@@ -53,11 +41,11 @@ import java.util.List;
 
 public abstract class KdcRequest {
 
-    protected KdcContext kdcContext;
+    private final KdcReq kdcReq;
+    private final KdcContext kdcContext;
 
     private Ticket ticket;
     private boolean isPreAuthenticated;
-    private KdcReq kdcReq;
     private KdcRep reply;
     private InetAddress clientAddress;
     private boolean isTcp = true;
@@ -74,6 +62,7 @@ public abstract class KdcRequest {
     public KdcRequest(KdcReq kdcReq, KdcContext kdcContext) {
         this.kdcReq = kdcReq;
         this.kdcContext = kdcContext;
+
         this.preauthContext = kdcContext.getPreauthHandler()
                 .preparePreauthContext(this);
         this.fastContext = new KdcFastContext();
@@ -83,6 +72,10 @@ public abstract class KdcRequest {
         return kdcContext;
     }
 
+    public KdcReq getKdcReq() {
+        return kdcReq;
+    }
+
     public PreauthContext getPreauthContext() {
         return preauthContext;
     }
@@ -97,10 +90,6 @@ public abstract class KdcRequest {
         makeReply();
     }
 
-    public KdcReq getKdcReq() {
-        return kdcReq;
-    }
-
     public KrbIdentity getTgsEntry() {
         return tgsEntry;
     }
@@ -275,149 +264,7 @@ public abstract class KdcRequest {
         checkPolicy();
     }
 
-    protected void issueTicket() throws KrbException {
-        KdcReq request = getKdcReq();
-
-        EncryptionType encryptionType = getEncryptionType();
-        EncryptionKey serverKey = getServerEntry().getKeys().get(encryptionType);
-
-        PrincipalName ticketPrincipal = getIssueTicketServerPrincipal();
-
-        EncTicketPart encTicketPart = new EncTicketPart();
-        KdcConfig config = kdcContext.getConfig();
-
-        TicketFlags ticketFlags = new TicketFlags();
-        encTicketPart.setFlags(ticketFlags);
-        ticketFlags.setFlag(TicketFlag.INITIAL);
-
-        if (isPreAuthenticated()) {
-            ticketFlags.setFlag(TicketFlag.PRE_AUTH);
-        }
-
-        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.FORWARDABLE)) {
-            if (!config.isForwardableAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.FORWARDABLE);
-        }
-
-        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.PROXIABLE)) {
-            if (!config.isProxiableAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.PROXIABLE);
-        }
-
-        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.ALLOW_POSTDATE)) {
-            if (!config.isPostdatedAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.MAY_POSTDATE);
-        }
-
-        KdcOptions kdcOptions = request.getReqBody().getKdcOptions();
-
-        EncryptionKey sessionKey = EncryptionHandler.random2Key(getEncryptionType());
-        encTicketPart.setKey(sessionKey);
-
-        encTicketPart.setCname(getIssueTicketClientPrincipal());
-        encTicketPart.setCrealm(request.getReqBody().getRealm());
-
-        TransitedEncoding transEnc = new TransitedEncoding();
-        encTicketPart.setTransited(transEnc);
-        String serverRealm = request.getReqBody().getRealm();
-
-        KerberosTime now = KerberosTime.now();
-        encTicketPart.setAuthTime(now);
-
-        KerberosTime krbStartTime = request.getReqBody().getFrom();
-        if (krbStartTime == null || krbStartTime.lessThan(now) ||
-                krbStartTime.isInClockSkew(config.getAllowableClockSkew())) {
-            krbStartTime = now;
-        }
-        if (krbStartTime.greaterThan(now)
-                && !krbStartTime.isInClockSkew(config.getAllowableClockSkew())
-                && !kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_CANNOT_POSTDATE);
-        }
-
-        if (kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
-            if (!config.isPostdatedAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.POSTDATED);
-            encTicketPart.setStartTime(krbStartTime);
-        }
-
-        KerberosTime krbEndTime = request.getReqBody().getTill();
-        if (krbEndTime == null || krbEndTime.getTime() == 0) {
-            krbEndTime = krbStartTime.extend(config.getMaximumTicketLifetime() * 1000);
-        } else if (krbStartTime.greaterThan(krbEndTime)) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
-        }
-        encTicketPart.setEndTime(krbEndTime);
-
-        long ticketLifeTime = Math.abs(krbEndTime.diff(krbStartTime));
-        if (ticketLifeTime < config.getMinimumTicketLifetime()) {
-            throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
-        }
-
-        KerberosTime krbRtime = request.getReqBody().getRtime();
-        if (kdcOptions.isFlagSet(KdcOption.RENEWABLE_OK)) {
-            kdcOptions.setFlag(KdcOption.RENEWABLE);
-        }
-        if (kdcOptions.isFlagSet(KdcOption.RENEWABLE)) {
-            if (!config.isRenewableAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-
-            ticketFlags.setFlag(TicketFlag.RENEWABLE);
-
-            if (krbRtime == null || krbRtime.getTime() == 0) {
-                krbRtime = KerberosTime.NEVER;
-            }
-            KerberosTime allowedMaximumRenewableTime = krbStartTime;
-            allowedMaximumRenewableTime.extend(config.getMaximumRenewableLifetime() * 1000);
-            if (krbRtime.greaterThan(allowedMaximumRenewableTime)) {
-                krbRtime = allowedMaximumRenewableTime;
-            }
-            encTicketPart.setRenewtill(krbRtime);
-        }
-
-        HostAddresses hostAddresses = request.getReqBody().getAddresses();
-        if (hostAddresses == null || hostAddresses.isEmpty()) {
-            if (!config.isEmptyAddressesAllowed()) {
-                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
-            }
-        } else {
-            encTicketPart.setClientAddresses(hostAddresses);
-        }
-
-        EncryptedData encryptedData = EncryptionUtil.seal(encTicketPart,
-                serverKey, KeyUsage.KDC_REP_TICKET);
-
-        Ticket newTicket = new Ticket();
-        newTicket.setSname(ticketPrincipal);
-        newTicket.setEncryptedEncPart(encryptedData);
-        newTicket.setRealm(serverRealm);
-        newTicket.setEncPart(encTicketPart);
-
-        setTicket(newTicket);
-    }
-
-    protected PrincipalName getIssueTicketServerPrincipal() {
-        KdcReq request = getKdcReq();
-        return request.getReqBody().getSname();
-    }
-
-    protected PrincipalName getIssueTicketClientPrincipal() {
-        KdcReq request = getKdcReq();
-        return request.getReqBody().getCname();
-    }
+    protected abstract void issueTicket() throws KrbException;
 
     private void checkServer() throws KrbException {
         KdcReq request = getKdcReq();

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/ServiceTickertIssuer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/ServiceTickertIssuer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/ServiceTickertIssuer.java
new file mode 100644
index 0000000..ee30ee9
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/ServiceTickertIssuer.java
@@ -0,0 +1,50 @@
+/**
+ *  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.server.request;
+
+import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
+import org.apache.kerby.kerberos.kerb.spec.base.TransitedEncoding;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+
+/**
+ * Issuing service ticket.
+ */
+public class ServiceTickertIssuer extends TickertIssuer {
+    private final Ticket tgtTicket;
+
+    public ServiceTickertIssuer(TgsRequest kdcRequest) {
+        super(kdcRequest);
+        tgtTicket = kdcRequest.getTgtTicket();
+    }
+
+    protected KdcRequest getTgsRequest() {
+        return getKdcRequest();
+    }
+
+    @Override
+    protected PrincipalName getclientPrincipal() {
+        return tgtTicket.getEncPart().getCname();
+    }
+
+    @Override
+    protected TransitedEncoding getTransitedEncoding() {
+        return tgtTicket.getEncPart().getTransited();
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
index 9088bd6..34e21c2 100644
--- a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgsRequest.java
@@ -58,17 +58,20 @@ public class TgsRequest extends KdcRequest {
         this.tgtSessionKey = tgtSessionKey;
     }
 
-    protected PrincipalName getIssueTicketServerPrincipal() {
-        return tgtTicket.getSname();
+    @Override
+    protected void checkClient() throws KrbException {
+        // Nothing to do at this phase because client couldn't be checked out yet.
     }
 
-    protected PrincipalName getIssueTicketClientPrincipal() {
-        return tgtTicket.getEncPart().getCname();
+    protected Ticket getTgtTicket() {
+        return tgtTicket;
     }
 
     @Override
-    protected void checkClient() throws KrbException {
-        // Nothing to do at this phase because client couldn't be checked out yet.
+    protected void issueTicket() throws KrbException {
+        TickertIssuer issuer = new ServiceTickertIssuer(this);
+        Ticket newTicket = issuer.issueTicket();
+        setTicket(newTicket);
     }
 
     public void verifyAuthenticator(PaDataEntry paDataEntry) throws KrbException {
@@ -109,7 +112,7 @@ public class TgsRequest extends KdcRequest {
 
         HostAddresses hostAddresses = tgtTicket.getEncPart().getClientAddresses();
         if (hostAddresses == null || hostAddresses.isEmpty()) {
-            if (!kdcContext.getConfig().isEmptyAddressesAllowed()) {
+            if (!getKdcContext().getConfig().isEmptyAddressesAllowed()) {
                 throw new KrbException(KrbErrorCode.KRB_AP_ERR_BADADDR);
             }
         } else if (!hostAddresses.contains(getClientAddress())) {
@@ -124,7 +127,7 @@ public class TgsRequest extends KdcRequest {
         setClientEntry(clientEntry);
 
         if (!authenticator.getCtime().isInClockSkew(
-                kdcContext.getConfig().getAllowableClockSkew() * 1000)) {
+                getKdcContext().getConfig().getAllowableClockSkew() * 1000)) {
             throw new KrbException(KrbErrorCode.KRB_AP_ERR_SKEW);
         }
 
@@ -154,7 +157,7 @@ public class TgsRequest extends KdcRequest {
         TgsRep reply = new TgsRep();
 
         reply.setCname(getClientEntry().getPrincipal());
-        reply.setCrealm(kdcContext.getKdcRealm());
+        reply.setCrealm(getKdcContext().getKdcRealm());
         reply.setTicket(ticket);
 
         EncKdcRepPart encKdcRepPart = makeEncKdcRepPart();

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgtTickertIssuer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgtTickertIssuer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgtTickertIssuer.java
new file mode 100644
index 0000000..4003f95
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TgtTickertIssuer.java
@@ -0,0 +1,43 @@
+/**
+ *  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.server.request;
+
+import org.apache.kerby.kerberos.kerb.spec.base.TransitedEncoding;
+import org.apache.kerby.kerberos.kerb.spec.base.TransitedEncodingType;
+
+/**
+ * Issuing TGT ticket.
+ */
+public class TgtTickertIssuer extends TickertIssuer {
+
+    public TgtTickertIssuer(AsRequest kdcRequest) {
+        super(kdcRequest);
+    }
+
+    @Override
+    protected TransitedEncoding getTransitedEncoding() {
+        TransitedEncoding transEnc = new TransitedEncoding();
+        transEnc.setTrType(TransitedEncodingType.DOMAIN_X500_COMPRESS);
+        byte[] empty = new byte[0];
+        transEnc.setContents(empty);
+
+        return transEnc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/6de5ada9/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
new file mode 100644
index 0000000..372bd02
--- /dev/null
+++ b/kerby-kerb/kerb-server/src/main/java/org/apache/kerby/kerberos/kerb/server/request/TickertIssuer.java
@@ -0,0 +1,231 @@
+/**
+ *  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.server.request;
+
+import org.apache.kerby.kerberos.kerb.KrbErrorCode;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
+import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcContext;
+import org.apache.kerby.kerberos.kerb.spec.KerberosTime;
+import org.apache.kerby.kerberos.kerb.spec.base.*;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOption;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcOptions;
+import org.apache.kerby.kerberos.kerb.spec.kdc.KdcReq;
+import org.apache.kerby.kerberos.kerb.spec.ticket.EncTicketPart;
+import org.apache.kerby.kerberos.kerb.spec.ticket.Ticket;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlag;
+import org.apache.kerby.kerberos.kerb.spec.ticket.TicketFlags;
+
+/**
+ * Handling ticket constructing, filling, and issuing.
+ */
+public abstract class TickertIssuer {
+    private final KdcRequest kdcRequest;
+
+    public TickertIssuer(KdcRequest kdcRequest) {
+        this.kdcRequest = kdcRequest;
+    }
+
+    protected KdcRequest getKdcRequest() {
+        return kdcRequest;
+    }
+
+    public Ticket issueTicket() throws KrbException {
+        KdcReq request = kdcRequest.getKdcReq();
+
+        Ticket issuedTicket = new Ticket();
+
+        PrincipalName serverPrincipal = getServerPrincipal();
+        issuedTicket.setSname(serverPrincipal);
+
+        String serverRealm = request.getReqBody().getRealm();
+        issuedTicket.setRealm(serverRealm);
+
+        EncTicketPart encTicketPart = makeEncTicketPart();
+
+        EncryptionKey encryptionKey = getTicketEncryptionKey();
+
+        EncryptedData encryptedData = EncryptionUtil.seal(encTicketPart,
+                encryptionKey, KeyUsage.KDC_REP_TICKET);
+        issuedTicket.setEncryptedEncPart(encryptedData);
+        issuedTicket.setEncPart(encTicketPart);
+
+        return issuedTicket;
+    }
+
+    public EncTicketPart makeEncTicketPart() throws KrbException {
+        KdcReq request = kdcRequest.getKdcReq();
+
+        EncTicketPart encTicketPart = new EncTicketPart();
+        KdcConfig config = kdcRequest.getKdcContext().getConfig();
+
+        TicketFlags ticketFlags = new TicketFlags();
+        encTicketPart.setFlags(ticketFlags);
+        ticketFlags.setFlag(TicketFlag.INITIAL);
+
+        if (kdcRequest.isPreAuthenticated()) {
+            ticketFlags.setFlag(TicketFlag.PRE_AUTH);
+        }
+
+        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.FORWARDABLE)) {
+            if (!config.isForwardableAllowed()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+            }
+
+            ticketFlags.setFlag(TicketFlag.FORWARDABLE);
+        }
+
+        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.PROXIABLE)) {
+            if (!config.isProxiableAllowed()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+            }
+
+            ticketFlags.setFlag(TicketFlag.PROXIABLE);
+        }
+
+        if (request.getReqBody().getKdcOptions().isFlagSet(KdcOption.ALLOW_POSTDATE)) {
+            if (!config.isPostdatedAllowed()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+            }
+
+            ticketFlags.setFlag(TicketFlag.MAY_POSTDATE);
+        }
+
+        EncryptionKey sessionKey = EncryptionHandler.random2Key(
+                kdcRequest.getEncryptionType());
+        encTicketPart.setKey(sessionKey);
+
+        encTicketPart.setCname(getclientPrincipal());
+        encTicketPart.setCrealm(request.getReqBody().getRealm());
+
+        TransitedEncoding transEnc = getTransitedEncoding();
+        encTicketPart.setTransited(transEnc);
+
+        KdcOptions kdcOptions = request.getReqBody().getKdcOptions();
+
+        KerberosTime now = KerberosTime.now();
+        encTicketPart.setAuthTime(now);
+
+        KerberosTime krbStartTime = request.getReqBody().getFrom();
+        if (krbStartTime == null || krbStartTime.lessThan(now) ||
+                krbStartTime.isInClockSkew(config.getAllowableClockSkew())) {
+            krbStartTime = now;
+        }
+        if (krbStartTime.greaterThan(now)
+                && !krbStartTime.isInClockSkew(config.getAllowableClockSkew())
+                && !kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
+            throw new KrbException(KrbErrorCode.KDC_ERR_CANNOT_POSTDATE);
+        }
+
+        if (kdcOptions.isFlagSet(KdcOption.POSTDATED)) {
+            if (!config.isPostdatedAllowed()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+            }
+
+            ticketFlags.setFlag(TicketFlag.POSTDATED);
+            encTicketPart.setStartTime(krbStartTime);
+        }
+
+        KerberosTime krbEndTime = request.getReqBody().getTill();
+        if (krbEndTime == null || krbEndTime.getTime() == 0) {
+            krbEndTime = krbStartTime.extend(config.getMaximumTicketLifetime() * 1000);
+        } else if (krbStartTime.greaterThan(krbEndTime)) {
+            throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
+        }
+        encTicketPart.setEndTime(krbEndTime);
+
+        long ticketLifeTime = Math.abs(krbEndTime.diff(krbStartTime));
+        if (ticketLifeTime < config.getMinimumTicketLifetime()) {
+            throw new KrbException(KrbErrorCode.KDC_ERR_NEVER_VALID);
+        }
+
+        KerberosTime krbRtime = request.getReqBody().getRtime();
+        if (kdcOptions.isFlagSet(KdcOption.RENEWABLE_OK)) {
+            kdcOptions.setFlag(KdcOption.RENEWABLE);
+        }
+        if (kdcOptions.isFlagSet(KdcOption.RENEWABLE)) {
+            if (!config.isRenewableAllowed()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+            }
+
+            ticketFlags.setFlag(TicketFlag.RENEWABLE);
+
+            if (krbRtime == null || krbRtime.getTime() == 0) {
+                krbRtime = KerberosTime.NEVER;
+            }
+            KerberosTime allowedMaximumRenewableTime = krbStartTime;
+            allowedMaximumRenewableTime.extend(config.getMaximumRenewableLifetime() * 1000);
+            if (krbRtime.greaterThan(allowedMaximumRenewableTime)) {
+                krbRtime = allowedMaximumRenewableTime;
+            }
+            encTicketPart.setRenewtill(krbRtime);
+        }
+
+        HostAddresses hostAddresses = request.getReqBody().getAddresses();
+        if (hostAddresses == null || hostAddresses.isEmpty()) {
+            if (!config.isEmptyAddressesAllowed()) {
+                throw new KrbException(KrbErrorCode.KDC_ERR_POLICY);
+            }
+        } else {
+            encTicketPart.setClientAddresses(hostAddresses);
+        }
+
+        return encTicketPart;
+    }
+
+    protected KdcContext getKdcContext() {
+        return kdcRequest.getKdcContext();
+    }
+
+    protected KdcReq getKdcReq() {
+        return kdcRequest.getKdcReq();
+    }
+
+    protected PrincipalName getclientPrincipal() {
+        return getKdcReq().getReqBody().getCname();
+    }
+
+    protected PrincipalName getServerPrincipal() {
+        return getKdcReq().getReqBody().getSname();
+    }
+
+    protected EncryptionType getTicketEncryptionType() throws KrbException {
+        EncryptionType encryptionType = kdcRequest.getEncryptionType();
+        return encryptionType;
+    }
+
+    protected EncryptionKey getTicketEncryptionKey() throws KrbException {
+        EncryptionType encryptionType = getTicketEncryptionType();
+        EncryptionKey serverKey =
+                kdcRequest.getServerEntry().getKeys().get(encryptionType);
+        return serverKey;
+    }
+
+    protected TransitedEncoding getTransitedEncoding() {
+        TransitedEncoding transEnc = new TransitedEncoding();
+        transEnc.setTrType(TransitedEncodingType.DOMAIN_X500_COMPRESS);
+        byte[] empty = new byte[0];
+        transEnc.setContents(empty);
+
+        return transEnc;
+    }
+}