You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2007/10/31 21:37:25 UTC

svn commit: r590816 - in /directory/apacheds/branches/bigbang: kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/ kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/service/ protocol-changepw/src/main/java...

Author: elecharny
Date: Wed Oct 31 13:37:23 2007
New Revision: 590816

URL: http://svn.apache.org/viewvc?rev=590816&view=rev
Log:
Removed the changepw chain, moved some commonly used methods into KerberosUtils

Added:
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordService.java
    directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java
Removed:
    directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/service/VerifyAuthHeader.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/BuildReply.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ConfigureChangePasswordChain.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ExtractPassword.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/GetAuthHeader.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/GetServerEntry.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/MonitorContext.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/MonitorReply.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/MonitorRequest.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ProcessPasswordChange.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/VerifyServiceTicket.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/VerifyServiceTicketAuthHeader.java
Modified:
    directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/KerberosUtils.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/protocol/ChangePasswordProtocolHandler.java
    directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordChain.java
    directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetRequestPrincipalEntry.java
    directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetTicketPrincipalEntry.java
    directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/VerifyTgtAuthHeader.java
    directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/protocol/KerberosProtocolHandler.java

Modified: directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/KerberosUtils.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/KerberosUtils.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/KerberosUtils.java (original)
+++ directory/apacheds/branches/bigbang/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/KerberosUtils.java Wed Oct 31 13:37:23 2007
@@ -19,6 +19,7 @@
  */
 package org.apache.directory.server.kerberos.shared;
 
+import java.net.InetAddress;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.List;
@@ -26,8 +27,24 @@
 
 import javax.security.auth.kerberos.KerberosPrincipal;
 
+import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
 import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
+import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
+import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
+import org.apache.directory.server.kerberos.shared.messages.ApplicationRequest;
+import org.apache.directory.server.kerberos.shared.messages.components.Authenticator;
+import org.apache.directory.server.kerberos.shared.messages.components.EncTicketPart;
+import org.apache.directory.server.kerberos.shared.messages.components.Ticket;
+import org.apache.directory.server.kerberos.shared.messages.value.ApOptions;
+import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
+import org.apache.directory.server.kerberos.shared.messages.value.HostAddress;
+import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
 import org.apache.directory.server.kerberos.shared.messages.value.PrincipalName;
+import org.apache.directory.server.kerberos.shared.messages.value.TicketFlags;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
 import org.apache.directory.shared.ldap.util.StringTools;
 
 /**
@@ -272,5 +289,173 @@
         }
 
         return sb.toString();
+    }
+
+
+    /**
+     * Get a PrincipalStoreEntry given a principal.  The ErrorType is used to indicate
+     * whether any resulting error pertains to a server or client.
+     *
+     * @param principal
+     * @param store
+     * @param errorType
+     * @return The PrincipalStoreEntry
+     * @throws Exception
+     */
+    public static PrincipalStoreEntry getEntry( KerberosPrincipal principal, PrincipalStore store, ErrorType errorType )
+        throws KerberosException
+    {
+        PrincipalStoreEntry entry = null;
+
+        try
+        {
+            entry = store.getPrincipal( principal );
+        }
+        catch ( Exception e )
+        {
+            throw new KerberosException( errorType, e );
+        }
+
+        if ( entry == null )
+        {
+            throw new KerberosException( errorType );
+        }
+
+        if ( entry.getKeyMap() == null || entry.getKeyMap().isEmpty() )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_NULL_KEY );
+        }
+
+        return entry;
+    }
+
+
+    /**
+     * Verifies an AuthHeader using guidelines from RFC 1510 section A.10., "KRB_AP_REQ verification."
+     *
+     * @param authHeader
+     * @param ticket
+     * @param serverKey
+     * @param clockSkew
+     * @param replayCache
+     * @param emptyAddressesAllowed
+     * @param clientAddress
+     * @param lockBox
+     * @param authenticatorKeyUsage
+     * @param isValidate
+     * @return The authenticator.
+     * @throws KerberosException
+     */
+    public static Authenticator verifyAuthHeader( ApplicationRequest authHeader, Ticket ticket, EncryptionKey serverKey,
+        long clockSkew, ReplayCache replayCache, boolean emptyAddressesAllowed, InetAddress clientAddress,
+        CipherTextHandler lockBox, KeyUsage authenticatorKeyUsage, boolean isValidate ) throws KerberosException
+    {
+        if ( authHeader.getProtocolVersionNumber() != KerberosConstants.KERBEROS_V5 )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_BADVERSION );
+        }
+
+        if ( authHeader.getMessageType() != KerberosMessageType.AP_REQ )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_MSG_TYPE );
+        }
+
+        if ( authHeader.getTicket().getTktVno() != KerberosConstants.KERBEROS_V5 )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_BADVERSION );
+        }
+
+        EncryptionKey ticketKey = null;
+
+        if ( authHeader.getOption( ApOptions.USE_SESSION_KEY ) )
+        {
+            ticketKey = authHeader.getTicket().getEncTicketPart().getSessionKey();
+        }
+        else
+        {
+            ticketKey = serverKey;
+        }
+
+        if ( ticketKey == null )
+        {
+            // TODO - check server key version number, skvno; requires store
+            if ( false )
+            {
+                throw new KerberosException( ErrorType.KRB_AP_ERR_BADKEYVER );
+            }
+
+            throw new KerberosException( ErrorType.KRB_AP_ERR_NOKEY );
+        }
+
+        EncTicketPart encPart = ( EncTicketPart ) lockBox.unseal( EncTicketPart.class, ticketKey, ticket.getEncPart(),
+            KeyUsage.NUMBER2 );
+        ticket.setEncTicketPart( encPart );
+
+        Authenticator authenticator = ( Authenticator ) lockBox.unseal( Authenticator.class, ticket.getEncTicketPart().getSessionKey(),
+            authHeader.getEncPart(), authenticatorKeyUsage );
+
+        if ( !authenticator.getClientPrincipal().getName().equals( ticket.getEncTicketPart().getClientPrincipal().getName() ) )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_BADMATCH );
+        }
+
+        if ( ticket.getEncTicketPart().getClientAddresses() != null )
+        {
+            if ( !ticket.getEncTicketPart().getClientAddresses().contains( new HostAddress( clientAddress ) ) )
+            {
+                throw new KerberosException( ErrorType.KRB_AP_ERR_BADADDR );
+            }
+        }
+        else
+        {
+            if ( !emptyAddressesAllowed )
+            {
+                throw new KerberosException( ErrorType.KRB_AP_ERR_BADADDR );
+            }
+        }
+
+        KerberosPrincipal serverPrincipal = ticket.getServerPrincipal();
+        KerberosPrincipal clientPrincipal = authenticator.getClientPrincipal();
+        KerberosTime clientTime = authenticator.getClientTime();
+        int clientMicroSeconds = authenticator.getClientMicroSecond();
+
+        if ( replayCache.isReplay( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ) )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_REPEAT );
+        }
+
+        replayCache.save( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds );
+
+        if ( !authenticator.getClientTime().isInClockSkew( clockSkew ) )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_SKEW );
+        }
+
+        /*
+         * "The server computes the age of the ticket: local (server) time minus
+         * the starttime inside the Ticket.  If the starttime is later than the
+         * current time by more than the allowable clock skew, or if the INVALID
+         * flag is set in the ticket, the KRB_AP_ERR_TKT_NYV error is returned."
+         */
+        KerberosTime startTime = ( ticket.getEncTicketPart().getStartTime() != null ) ? ticket.getEncTicketPart().getStartTime() : ticket.getEncTicketPart().getAuthTime();
+
+        KerberosTime now = new KerberosTime();
+        boolean isValidStartTime = startTime.lessThan( now );
+
+        if ( !isValidStartTime || ( ticket.getEncTicketPart().getFlags().get( TicketFlags.INVALID ) && !isValidate ) )
+        {
+            // it hasn't yet become valid
+            throw new KerberosException( ErrorType.KRB_AP_ERR_TKT_NYV );
+        }
+
+        // TODO - doesn't take into account skew
+        if ( !ticket.getEncTicketPart().getEndTime().greaterThan( now ) )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_TKT_EXPIRED );
+        }
+
+        authHeader.setOption( ApOptions.MUTUAL_REQUIRED );
+
+        return authenticator;
     }
 }

Modified: directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/protocol/ChangePasswordProtocolHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/protocol/ChangePasswordProtocolHandler.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/protocol/ChangePasswordProtocolHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/protocol/ChangePasswordProtocolHandler.java Wed Oct 31 13:37:23 2007
@@ -35,6 +35,7 @@
 import org.apache.directory.server.changepw.messages.ChangePasswordRequest;
 import org.apache.directory.server.changepw.service.ChangePasswordChain;
 import org.apache.directory.server.changepw.service.ChangePasswordContext;
+import org.apache.directory.server.changepw.service.ChangePasswordService;
 import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
 import org.apache.directory.server.kerberos.shared.messages.ErrorMessage;
 import org.apache.directory.server.kerberos.shared.messages.ErrorMessageModifier;
@@ -60,7 +61,7 @@
 
     private ChangePasswordServer config;
     private PrincipalStore store;
-    private IoHandlerCommand changepwService;
+    //private IoHandlerCommand changepwService;
     private String contextKey = "context";
 
 
@@ -75,7 +76,7 @@
         this.config = config;
         this.store = store;
 
-        changepwService = new ChangePasswordChain();
+        //changepwService = new ChangePasswordChain();
     }
 
 
@@ -140,7 +141,8 @@
             changepwContext.setRequest( request );
             session.setAttribute( getContextKey(), changepwContext );
 
-            changepwService.execute( null, session, message );
+            ChangePasswordService.execute( session, changepwContext );
+            //changepwService.execute( null, session, message );
 
             session.write( changepwContext.getReply() );
         }

Modified: directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordChain.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordChain.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordChain.java (original)
+++ directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordChain.java Wed Oct 31 13:37:23 2007
@@ -42,30 +42,30 @@
      */
     public ChangePasswordChain()
     {
-        if ( log.isDebugEnabled() )
-        {
-            addLast( "monitorRequest", new MonitorRequest() );
-        }
+        //if ( log.isDebugEnabled() )
+        //{
+        //    addLast( "monitorRequest", new MonitorRequest() );
+        //}
 
-        addLast( "configureChangePasswordChain", new ConfigureChangePasswordChain() );
-        addLast( "getAuthHeader", new GetAuthHeader() );
-        addLast( "verifyServiceTicket", new VerifyServiceTicket() );
-        addLast( "getServerEntry", new GetServerEntry() );
-        addLast( "verifyServiceTicketAuthHeader", new VerifyServiceTicketAuthHeader() );
+        //addLast( "configureChangePasswordChain", new ConfigureChangePasswordChain() );
+        //addLast( "getAuthHeader", new GetAuthHeader() );
+        //addLast( "verifyServiceTicket", new VerifyServiceTicket() );
+        //addLast( "getServerEntry", new GetServerEntry() );
+        //addLast( "verifyServiceTicketAuthHeader", new VerifyServiceTicketAuthHeader() );
 
-        addLast( "extractPassword", new ExtractPassword() );
+        //addLast( "extractPassword", new ExtractPassword() );
 
-        if ( log.isDebugEnabled() )
-        {
-            addLast( "monitorContext", new MonitorContext() );
-        }
+        //if ( log.isDebugEnabled() )
+        //{
+        //    addLast( "monitorContext", new MonitorContext() );
+        //}
 
-        addLast( "processPasswordChange", new ProcessPasswordChange() );
-        addLast( "buildReply", new BuildReply() );
+        //addLast( "processPasswordChange", new ProcessPasswordChange() );
+        //addLast( "buildReply", new BuildReply() );
 
-        if ( log.isDebugEnabled() )
-        {
-            addLast( "monitorReply", new MonitorReply() );
-        }
+        //if ( log.isDebugEnabled() )
+        //{
+        //    addLast( "monitorReply", new MonitorReply() );
+        //}
     }
 }

Added: directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordService.java?rev=590816&view=auto
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordService.java (added)
+++ directory/apacheds/branches/bigbang/protocol-changepw/src/main/java/org/apache/directory/server/changepw/service/ChangePasswordService.java Wed Oct 31 13:37:23 2007
@@ -0,0 +1,437 @@
+/*
+ *  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.directory.server.changepw.service;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import javax.naming.NamingException;
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.server.changepw.ChangePasswordServer;
+import org.apache.directory.server.changepw.exceptions.ChangePasswordException;
+import org.apache.directory.server.changepw.exceptions.ErrorType;
+import org.apache.directory.server.changepw.io.ChangePasswordDataDecoder;
+import org.apache.directory.server.changepw.messages.ChangePasswordReply;
+import org.apache.directory.server.changepw.messages.ChangePasswordReplyModifier;
+import org.apache.directory.server.changepw.messages.ChangePasswordRequest;
+import org.apache.directory.server.changepw.value.ChangePasswordData;
+import org.apache.directory.server.changepw.value.ChangePasswordDataModifier;
+import org.apache.directory.server.kerberos.shared.KerberosUtils;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
+import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
+//import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
+import org.apache.directory.server.kerberos.shared.messages.ApplicationRequest;
+import org.apache.directory.server.kerberos.shared.messages.application.ApplicationReply;
+import org.apache.directory.server.kerberos.shared.messages.application.PrivateMessage;
+import org.apache.directory.server.kerberos.shared.messages.components.Authenticator;
+import org.apache.directory.server.kerberos.shared.messages.components.EncApRepPart;
+import org.apache.directory.server.kerberos.shared.messages.components.EncApRepPartModifier;
+import org.apache.directory.server.kerberos.shared.messages.components.EncKrbPrivPart;
+import org.apache.directory.server.kerberos.shared.messages.components.EncKrbPrivPartModifier;
+import org.apache.directory.server.kerberos.shared.messages.components.Ticket;
+import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
+import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
+import org.apache.directory.server.kerberos.shared.messages.value.HostAddress;
+import org.apache.directory.server.kerberos.shared.messages.value.HostAddresses;
+import org.apache.directory.server.kerberos.shared.messages.value.TicketFlags;
+import org.apache.directory.server.kerberos.shared.replay.InMemoryReplayCache;
+import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
+import org.apache.mina.common.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ChangePasswordService
+{
+    /** the logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( ChangePasswordService.class );
+
+    private static final ReplayCache replayCache = new InMemoryReplayCache();
+    
+    private static final CipherTextHandler cipherTextHandler = new CipherTextHandler();
+
+    
+    public static void execute( IoSession session, ChangePasswordContext changepwContext ) throws KerberosException, IOException
+    {
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorRequest( changepwContext );
+        }
+        
+        configureChangePassword( changepwContext );
+        getAuthHeader( session, changepwContext );
+        verifyServiceTicket( changepwContext );
+        getServerEntry( changepwContext );
+        verifyServiceTicketAuthHeader( changepwContext );
+        extractPassword( changepwContext );
+        
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorContext( changepwContext );
+        }
+        
+        processPasswordChange( changepwContext );
+        buildReply( changepwContext );
+        
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorReply( changepwContext );
+        }
+    }
+    
+    
+    private static void processPasswordChange( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        PrincipalStore store = changepwContext.getStore();
+        Authenticator authenticator = changepwContext.getAuthenticator();
+        String newPassword = changepwContext.getPassword();
+        KerberosPrincipal clientPrincipal = authenticator.getClientPrincipal();
+
+        // usec and seq-number must be present per MS but aren't in legacy kpasswd
+        // seq-number must have same value as authenticator
+        // ignore r-address
+
+        try
+        {
+            String principalName = store.changePassword( clientPrincipal, newPassword );
+            LOG.debug( "Successfully modified principal {}.", principalName );
+        }
+        catch ( NamingException ne )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_SOFTERROR, ne.getExplanation().getBytes(), ne );
+        }
+        catch ( Exception e )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_HARDERROR, e );
+        }
+    }
+    
+    
+    private static void monitorRequest( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        try
+        {
+            ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+            short versionNumber = request.getVersionNumber();
+
+            StringBuffer sb = new StringBuffer();
+            sb.append( "Responding to change password request:" );
+            sb.append( "\n\t" + "versionNumber    " + versionNumber );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( "Error in request monitor", e );
+        }
+    }
+    
+    
+    private static void configureChangePassword( ChangePasswordContext changepwContext )
+    {
+        changepwContext.setReplayCache( replayCache );
+        changepwContext.setCipherTextHandler( cipherTextHandler );
+    }
+    
+    
+    private static void getAuthHeader( IoSession session, ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+
+        if ( request.getVersionNumber() != 1 )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_BAD_VERSION );
+        }
+
+        if ( request.getAuthHeader() == null || request.getAuthHeader().getTicket() == null )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_AUTHERROR );
+        }
+
+        ApplicationRequest authHeader = request.getAuthHeader();
+        Ticket ticket = authHeader.getTicket();
+
+        changepwContext.setAuthHeader( authHeader );
+        changepwContext.setTicket( ticket );
+    }
+    
+    
+    private static void verifyServiceTicket( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        ChangePasswordServer config = changepwContext.getConfig();
+        Ticket ticket = changepwContext.getTicket();
+        String primaryRealm = config.getPrimaryRealm();
+        KerberosPrincipal changepwPrincipal = config.getServicePrincipal();
+        KerberosPrincipal serverPrincipal = ticket.getServerPrincipal(); 
+
+        if ( !ticket.getRealm().equals( primaryRealm ) || !serverPrincipal.equals( changepwPrincipal ) )
+        {
+            throw new KerberosException( org.apache.directory.server.kerberos.shared.exceptions.ErrorType.KRB_AP_ERR_NOT_US );
+        }
+    }
+    
+    
+    private static void getServerEntry( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        KerberosPrincipal principal =  changepwContext.getTicket().getServerPrincipal();
+        PrincipalStore store = changepwContext.getStore();
+
+        changepwContext.setServerEntry( KerberosUtils.getEntry( principal, store, org.apache.directory.server.kerberos.shared.exceptions.ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN ) );
+    }
+    
+    
+    private static void verifyServiceTicketAuthHeader( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        ApplicationRequest authHeader = changepwContext.getAuthHeader();
+        Ticket ticket = changepwContext.getTicket();
+
+        EncryptionType encryptionType = ticket.getEncPart().getEType();
+        EncryptionKey serverKey = changepwContext.getServerEntry().getKeyMap().get( encryptionType );
+
+        long clockSkew = changepwContext.getConfig().getAllowableClockSkew();
+        ReplayCache replayCache = changepwContext.getReplayCache();
+        boolean emptyAddressesAllowed = changepwContext.getConfig().isEmptyAddressesAllowed();
+        InetAddress clientAddress = changepwContext.getClientAddress();
+        CipherTextHandler cipherTextHandler = changepwContext.getCipherTextHandler();
+
+        Authenticator authenticator = KerberosUtils.verifyAuthHeader( authHeader, ticket, serverKey, clockSkew, replayCache,
+            emptyAddressesAllowed, clientAddress, cipherTextHandler, KeyUsage.NUMBER11, false );
+
+        ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+
+        if ( request.getVersionNumber() == 1 && !ticket.getEncTicketPart().getFlags().get( TicketFlags.INITIAL ) )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_INITIAL_FLAG_NEEDED );
+        }
+
+        changepwContext.setAuthenticator( authenticator );
+    }
+    
+    
+    private static void extractPassword( ChangePasswordContext changepwContext ) throws KerberosException, IOException
+    {
+        ChangePasswordRequest request = ( ChangePasswordRequest ) changepwContext.getRequest();
+        Authenticator authenticator = changepwContext.getAuthenticator();
+        CipherTextHandler cipherTextHandler = changepwContext.getCipherTextHandler();
+
+        // TODO - check ticket is for service authorized to change passwords
+        // ticket.getServerPrincipal().getName().equals(config.getChangepwPrincipal().getName()));
+
+        // TODO - check client principal in ticket is authorized to change password
+
+        // get the subsession key from the Authenticator
+        EncryptionKey subSessionKey = authenticator.getSubSessionKey();
+
+        // decrypt the request's private message with the subsession key
+        EncryptedData encReqPrivPart = request.getPrivateMessage().getEncryptedPart();
+
+        EncKrbPrivPart privatePart;
+
+        try
+        {
+            privatePart = ( EncKrbPrivPart ) cipherTextHandler.unseal( EncKrbPrivPart.class, subSessionKey,
+                encReqPrivPart, KeyUsage.NUMBER13 );
+        }
+        catch ( KerberosException ke )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_SOFTERROR, ke );
+        }
+
+        ChangePasswordData passwordData = null;
+
+        if ( request.getVersionNumber() == ( short ) 1 )
+        {
+            // Use protocol version 0x0001, the legacy Kerberos change password protocol
+            ChangePasswordDataModifier modifier = new ChangePasswordDataModifier();
+            modifier.setNewPassword( privatePart.getUserData() );
+            passwordData = modifier.getChangePasswdData();
+        }
+        else
+        {
+            // Use protocol version 0xFF80, the backwards-compatible MS protocol
+            ChangePasswordDataDecoder passwordDecoder = new ChangePasswordDataDecoder();
+            passwordData = passwordDecoder.decodeChangePasswordData( privatePart.getUserData() );
+        }
+
+        try
+        {
+            changepwContext.setPassword( new String( passwordData.getPassword(), "UTF-8" ) );
+        }
+        catch ( UnsupportedEncodingException uee )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_SOFTERROR, uee );
+        }
+    }
+
+    
+    private static void monitorContext( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        try
+        {
+            PrincipalStore store = changepwContext.getStore();
+            ApplicationRequest authHeader = changepwContext.getAuthHeader();
+            Ticket ticket = changepwContext.getTicket();
+            ReplayCache replayCache = changepwContext.getReplayCache();
+            long clockSkew = changepwContext.getConfig().getAllowableClockSkew();
+
+            Authenticator authenticator = changepwContext.getAuthenticator();
+            KerberosPrincipal clientPrincipal = authenticator.getClientPrincipal();
+            String desiredPassword = changepwContext.getPassword();
+
+            InetAddress clientAddress = changepwContext.getClientAddress();
+            HostAddresses clientAddresses = ticket.getEncTicketPart().getClientAddresses();
+
+            boolean caddrContainsSender = false;
+
+            if ( ticket.getEncTicketPart().getClientAddresses() != null )
+            {
+                caddrContainsSender = ticket.getEncTicketPart().getClientAddresses().contains( new HostAddress( clientAddress ) );
+            }
+
+            StringBuffer sb = new StringBuffer();
+            sb.append( "Monitoring context:" );
+            sb.append( "\n\t" + "store                  " + store );
+            sb.append( "\n\t" + "authHeader             " + authHeader );
+            sb.append( "\n\t" + "ticket                 " + ticket );
+            sb.append( "\n\t" + "replayCache            " + replayCache );
+            sb.append( "\n\t" + "clockSkew              " + clockSkew );
+            sb.append( "\n\t" + "clientPrincipal        " + clientPrincipal );
+            sb.append( "\n\t" + "desiredPassword        " + desiredPassword );
+            sb.append( "\n\t" + "clientAddress          " + clientAddress );
+            sb.append( "\n\t" + "clientAddresses        " + clientAddresses );
+            sb.append( "\n\t" + "caddr contains sender  " + caddrContainsSender );
+            sb.append( "\n\t" + "Ticket principal       " + ticket.getServerPrincipal() );
+
+            PrincipalStoreEntry ticketPrincipal = changepwContext.getServerEntry();
+            
+            sb.append( "\n\t" + "cn                     " + ticketPrincipal.getCommonName() );
+            sb.append( "\n\t" + "realm                  " + ticketPrincipal.getRealmName() );
+            sb.append( "\n\t" + "Service principal      " + ticketPrincipal.getPrincipal() );
+            sb.append( "\n\t" + "SAM type               " + ticketPrincipal.getSamType() );
+
+            EncryptionType encryptionType = ticket.getEncPart().getEType();
+            int keyVersion = ticketPrincipal.getKeyMap().get( encryptionType ).getKeyVersion();
+            sb.append( "\n\t" + "Ticket key type        " + encryptionType );
+            sb.append( "\n\t" + "Service key version    " + keyVersion );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( "Error in context monitor", e );
+        }
+    }
+    
+    
+    private static void buildReply( ChangePasswordContext changepwContext ) throws KerberosException, UnknownHostException
+    {
+        Authenticator authenticator = changepwContext.getAuthenticator();
+        Ticket ticket = changepwContext.getTicket();
+        CipherTextHandler cipherTextHandler = changepwContext.getCipherTextHandler();
+
+        // begin building reply
+
+        // create priv message
+        // user-data component is short result code
+        EncKrbPrivPartModifier modifier = new EncKrbPrivPartModifier();
+        byte[] resultCode =
+            { ( byte ) 0x00, ( byte ) 0x00 };
+        modifier.setUserData( resultCode );
+
+        modifier.setSenderAddress( new HostAddress( InetAddress.getLocalHost() ) );
+        EncKrbPrivPart privPart = modifier.getEncKrbPrivPart();
+
+        // get the subsession key from the Authenticator
+        EncryptionKey subSessionKey = authenticator.getSubSessionKey();
+
+        EncryptedData encPrivPart;
+
+        try
+        {
+            encPrivPart = cipherTextHandler.seal( subSessionKey, privPart, KeyUsage.NUMBER13 );
+        }
+        catch ( KerberosException ke )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_SOFTERROR, ke );
+        }
+
+        PrivateMessage privateMessage = new PrivateMessage( encPrivPart );
+
+        // Begin AP_REP generation
+        EncApRepPartModifier encApModifier = new EncApRepPartModifier();
+        encApModifier.setClientTime( authenticator.getClientTime() );
+        encApModifier.setClientMicroSecond( authenticator.getClientMicroSecond() );
+        encApModifier.setSequenceNumber( new Integer( authenticator.getSequenceNumber() ) );
+        encApModifier.setSubSessionKey( authenticator.getSubSessionKey() );
+
+        EncApRepPart repPart = encApModifier.getEncApRepPart();
+
+        EncryptedData encRepPart;
+
+        try
+        {
+            encRepPart = cipherTextHandler.seal( ticket.getEncTicketPart().getSessionKey(), repPart, KeyUsage.NUMBER12 );
+        }
+        catch ( KerberosException ke )
+        {
+            throw new ChangePasswordException( ErrorType.KRB5_KPASSWD_SOFTERROR, ke );
+        }
+
+        ApplicationReply appReply = new ApplicationReply( encRepPart );
+
+        // return status message value object
+        ChangePasswordReplyModifier replyModifier = new ChangePasswordReplyModifier();
+        replyModifier.setApplicationReply( appReply );
+        replyModifier.setPrivateMessage( privateMessage );
+
+        changepwContext.setReply( replyModifier.getChangePasswordReply() );
+    }
+
+    
+    private static void monitorReply( ChangePasswordContext changepwContext ) throws KerberosException
+    {
+        try
+        {
+            ChangePasswordReply reply = ( ChangePasswordReply ) changepwContext.getReply();
+            ApplicationReply appReply = reply.getApplicationReply();
+            PrivateMessage priv = reply.getPrivateMessage();
+
+            StringBuilder sb = new StringBuilder();
+            sb.append( "Responding with change password reply:" );
+            sb.append( "\n\t" + "appReply               " + appReply );
+            sb.append( "\n\t" + "priv                   " + priv );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( "Error in reply monitor", e );
+        }
+    }
+}

Modified: directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetRequestPrincipalEntry.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetRequestPrincipalEntry.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetRequestPrincipalEntry.java (original)
+++ directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetRequestPrincipalEntry.java Wed Oct 31 13:37:23 2007
@@ -22,6 +22,7 @@
 
 import javax.security.auth.kerberos.KerberosPrincipal;
 
+import org.apache.directory.server.kerberos.shared.KerberosUtils;
 import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
 import org.apache.directory.server.kerberos.shared.service.GetPrincipalStoreEntry;
 import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
@@ -42,7 +43,7 @@
         KerberosPrincipal principal = tgsContext.getRequest().getServerPrincipal();
         PrincipalStore store = tgsContext.getStore();
 
-        PrincipalStoreEntry entry = getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN );
+        PrincipalStoreEntry entry = KerberosUtils.getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN );
         tgsContext.setRequestPrincipalEntry( entry );
 
         next.execute( session, message );

Modified: directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetTicketPrincipalEntry.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetTicketPrincipalEntry.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetTicketPrincipalEntry.java (original)
+++ directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/GetTicketPrincipalEntry.java Wed Oct 31 13:37:23 2007
@@ -22,6 +22,7 @@
 
 import javax.security.auth.kerberos.KerberosPrincipal;
 
+import org.apache.directory.server.kerberos.shared.KerberosUtils;
 import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
 import org.apache.directory.server.kerberos.shared.service.GetPrincipalStoreEntry;
 import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
@@ -42,7 +43,7 @@
         KerberosPrincipal principal = tgsContext.getTgt().getServerPrincipal();
         PrincipalStore store = tgsContext.getStore();
 
-        PrincipalStoreEntry entry = getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN );
+        PrincipalStoreEntry entry = KerberosUtils.getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN );
         tgsContext.setTicketPrincipalEntry( entry );
 
         next.execute( session, message );

Added: directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java?rev=590816&view=auto
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java (added)
+++ directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/TicketGrantingService.java Wed Oct 31 13:37:23 2007
@@ -0,0 +1,921 @@
+/*
+ *  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.directory.server.kerberos.kdc.ticketgrant;
+
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.kerberos.KerberosPrincipal;
+
+import org.apache.directory.server.kerberos.kdc.KdcContext;
+import org.apache.directory.server.kerberos.kdc.KdcServer;
+import org.apache.directory.server.kerberos.shared.KerberosConstants;
+import org.apache.directory.server.kerberos.shared.KerberosUtils;
+import org.apache.directory.server.kerberos.shared.crypto.checksum.ChecksumHandler;
+import org.apache.directory.server.kerberos.shared.crypto.checksum.ChecksumType;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
+import org.apache.directory.server.kerberos.shared.crypto.encryption.RandomKeyFactory;
+import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
+import org.apache.directory.server.kerberos.shared.exceptions.KerberosException;
+import org.apache.directory.server.kerberos.shared.io.decoder.ApplicationRequestDecoder;
+import org.apache.directory.server.kerberos.shared.messages.ApplicationRequest;
+import org.apache.directory.server.kerberos.shared.messages.KdcReply;
+import org.apache.directory.server.kerberos.shared.messages.KdcRequest;
+import org.apache.directory.server.kerberos.shared.messages.TicketGrantReply;
+import org.apache.directory.server.kerberos.shared.messages.components.Authenticator;
+import org.apache.directory.server.kerberos.shared.messages.components.EncTicketPart;
+import org.apache.directory.server.kerberos.shared.messages.components.EncTicketPartModifier;
+import org.apache.directory.server.kerberos.shared.messages.components.Ticket;
+import org.apache.directory.server.kerberos.shared.messages.value.AuthorizationData;
+import org.apache.directory.server.kerberos.shared.messages.value.Checksum;
+import org.apache.directory.server.kerberos.shared.messages.value.EncryptedData;
+import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
+import org.apache.directory.server.kerberos.shared.messages.value.HostAddress;
+import org.apache.directory.server.kerberos.shared.messages.value.HostAddresses;
+import org.apache.directory.server.kerberos.shared.messages.value.KdcOptions;
+import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
+import org.apache.directory.server.kerberos.shared.messages.value.LastRequest;
+import org.apache.directory.server.kerberos.shared.messages.value.PaData;
+import org.apache.directory.server.kerberos.shared.messages.value.TicketFlags;
+import org.apache.directory.server.kerberos.shared.messages.value.flags.TicketFlag;
+import org.apache.directory.server.kerberos.shared.messages.value.types.PaDataType;
+import org.apache.directory.server.kerberos.shared.replay.InMemoryReplayCache;
+import org.apache.directory.server.kerberos.shared.service.GetPrincipalStoreEntry;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStore;
+import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
+import org.apache.mina.common.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 583938 $, $Date: 2007-10-11 21:57:20 +0200 (Thu, 11 Oct 2007) $
+ */
+public class TicketGrantingService
+{
+    
+    /** the log for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( TicketGrantingService.class );
+    
+    private static final InMemoryReplayCache replayCache = new InMemoryReplayCache();
+    private static final CipherTextHandler cipherTextHandler = new CipherTextHandler();
+
+    private static final String CONTEXT_KEY = "context";
+    
+    private static final String SERVICE_NAME = "Ticket-Granting Service (TGS)";
+
+    private static final ChecksumHandler checksumHandler = new ChecksumHandler();
+
+    
+    public static void execute( IoSession session, TicketGrantingContext tgsContext ) throws Exception
+    {
+        KdcContext kdcContext = ( KdcContext ) session.getAttribute( CONTEXT_KEY );           
+
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorRequest( kdcContext );
+        }
+
+        // This is really strange that we have to configure the replay cache for every single request !!!
+        KdcServer config = tgsContext.getConfig();
+        long clockSkew = config.getAllowableClockSkew();
+        replayCache.setClockSkew( clockSkew );
+        tgsContext.setReplayCache( replayCache );
+
+        tgsContext.setCipherTextHandler( cipherTextHandler );
+
+        if ( tgsContext.getRequest().getProtocolVersionNumber() != KerberosConstants.KERBEROS_V5 )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_BAD_PVNO );
+        }
+
+        selectEncryptionType( kdcContext, tgsContext, session );
+        getAuthHeader( tgsContext, session );
+        verifyTgt( tgsContext, session );
+        getTicketPrincipalEntry( tgsContext, session );
+        verifyBodyChecksum( tgsContext, session );
+        getRequestPrincipalEntry( tgsContext, session );  
+        generateTicket( tgsContext, session );
+        buildReply( tgsContext, session );
+        
+        if ( LOG.isDebugEnabled() )
+        {
+            monitorContext( tgsContext );
+            monitorReply( session );
+        }
+        
+        sealReply( tgsContext, session );
+    }
+    
+
+    private static void monitorRequest( KdcContext kdcContext ) throws Exception
+    {
+        KdcRequest request = kdcContext.getRequest();
+
+        try
+        {
+            String clientAddress = kdcContext.getClientAddress().getHostAddress();
+
+            StringBuffer sb = new StringBuffer();
+
+            sb.append( "Received " + SERVICE_NAME + " request:" );
+            sb.append( "\n\t" + "messageType:           " + request.getMessageType() );
+            sb.append( "\n\t" + "protocolVersionNumber: " + request.getProtocolVersionNumber() );
+            sb.append( "\n\t" + "clientAddress:         " + clientAddress );
+            sb.append( "\n\t" + "nonce:                 " + request.getNonce() );
+            sb.append( "\n\t" + "kdcOptions:            " + request.getKdcOptions() );
+            sb.append( "\n\t" + "clientPrincipal:       " + request.getClientPrincipal() );
+            sb.append( "\n\t" + "serverPrincipal:       " + request.getServerPrincipal() );
+            sb.append( "\n\t" + "encryptionType:        " + KerberosUtils.getEncryptionTypesString( request.getEType() ) );
+            sb.append( "\n\t" + "realm:                 " + request.getRealm() );
+            sb.append( "\n\t" + "from time:             " + request.getFrom() );
+            sb.append( "\n\t" + "till time:             " + request.getTill() );
+            sb.append( "\n\t" + "renew-till time:       " + request.getRtime() );
+            sb.append( "\n\t" + "hostAddresses:         " + request.getAddresses() );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( "Error in request monitor", e );
+        }
+    }
+    
+    
+    private static void selectEncryptionType( KdcContext kdcContext, TicketGrantingContext tgsContext, IoSession session ) throws Exception
+    {
+        KdcServer config = kdcContext.getConfig();
+
+        Set<EncryptionType> requestedTypes = kdcContext.getRequest().getEType();
+
+        EncryptionType bestType = KerberosUtils.getBestEncryptionType( requestedTypes, config.getEncryptionTypes() );
+
+        LOG.debug( "Session will use encryption type {}.", bestType );
+
+        if ( bestType == null )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_ETYPE_NOSUPP );
+        }
+
+        kdcContext.setEncryptionType( bestType );
+    }
+    
+    
+    private static void getAuthHeader( TicketGrantingContext tgsContext, IoSession session ) throws Exception
+    {
+        KdcRequest request = tgsContext.getRequest();
+
+        ApplicationRequest authHeader = getAuthHeader( request );
+        Ticket tgt = authHeader.getTicket();
+
+        tgsContext.setAuthHeader( authHeader );
+        tgsContext.setTgt( tgt );
+    }
+    
+    
+    public static void verifyTgt( TicketGrantingContext tgsContext, IoSession session ) throws KerberosException
+    {
+        KdcServer config = tgsContext.getConfig();
+        Ticket tgt = tgsContext.getTgt();
+
+        // Check primary realm.
+        if ( !tgt.getRealm().equals( config.getPrimaryRealm() ) )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_NOT_US );
+        }
+
+        String tgtServerName = tgt.getServerPrincipal().getName();
+        String requestServerName = tgsContext.getRequest().getServerPrincipal().getName();
+
+        /*
+         * if (tgt.sname is not a TGT for local realm and is not req.sname)
+         *     then error_out(KRB_AP_ERR_NOT_US);
+         */    
+        if ( !tgtServerName.equals( config.getServicePrincipal().getName() )
+            && !tgtServerName.equals( requestServerName ) )
+        {
+            throw new KerberosException( ErrorType.KRB_AP_ERR_NOT_US );
+        }
+    }
+    
+    
+    private static void getTicketPrincipalEntry( TicketGrantingContext tgsContext, IoSession session ) throws KerberosException
+    {
+        KerberosPrincipal principal = tgsContext.getTgt().getServerPrincipal();
+        PrincipalStore store = tgsContext.getStore();
+
+        PrincipalStoreEntry entry = KerberosUtils.getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN );
+        tgsContext.setTicketPrincipalEntry( entry );
+    }
+
+    
+    
+    private static void verifyBodyChecksum( TicketGrantingContext tgsContext, IoSession session ) throws KerberosException
+    {
+        KdcServer config = tgsContext.getConfig();
+
+        if ( config.isBodyChecksumVerified() )
+        {
+            byte[] bodyBytes = tgsContext.getRequest().getBodyBytes();
+            Checksum authenticatorChecksum = tgsContext.getAuthenticator().getChecksum();
+
+            if ( authenticatorChecksum == null || authenticatorChecksum.getChecksumType() == null
+                || authenticatorChecksum.getChecksumValue() == null || bodyBytes == null )
+            {
+                throw new KerberosException( ErrorType.KRB_AP_ERR_INAPP_CKSUM );
+            }
+
+            LOG.debug( "Verifying body checksum type '{}'.", authenticatorChecksum.getChecksumType() );
+
+            checksumHandler.verifyChecksum( authenticatorChecksum, bodyBytes, null, KeyUsage.NUMBER8 );
+        }
+    }
+    
+
+    public static void getRequestPrincipalEntry( TicketGrantingContext tgsContext, IoSession session ) throws KerberosException
+    {
+        KerberosPrincipal principal = tgsContext.getRequest().getServerPrincipal();
+        PrincipalStore store = tgsContext.getStore();
+
+        PrincipalStoreEntry entry = KerberosUtils.getEntry( principal, store, ErrorType.KDC_ERR_S_PRINCIPAL_UNKNOWN );
+        tgsContext.setRequestPrincipalEntry( entry );
+    }
+
+    
+    private static void generateTicket( TicketGrantingContext tgsContext, IoSession session ) throws KerberosException
+    {
+        KdcRequest request = tgsContext.getRequest();
+        Ticket tgt = tgsContext.getTgt();
+        Authenticator authenticator = tgsContext.getAuthenticator();
+        CipherTextHandler cipherTextHandler = tgsContext.getCipherTextHandler();
+        KerberosPrincipal ticketPrincipal = request.getServerPrincipal();
+
+        EncryptionType encryptionType = tgsContext.getEncryptionType();
+        EncryptionKey serverKey = tgsContext.getRequestPrincipalEntry().getKeyMap().get( encryptionType );
+
+        KdcServer config = tgsContext.getConfig();
+
+        EncTicketPartModifier newTicketBody = new EncTicketPartModifier();
+
+        newTicketBody.setClientAddresses( tgt.getEncTicketPart().getClientAddresses() );
+
+        processFlags( config, request, tgt, newTicketBody );
+
+        EncryptionKey sessionKey = RandomKeyFactory.getRandomKey( tgsContext.getEncryptionType() );
+        newTicketBody.setSessionKey( sessionKey );
+
+        newTicketBody.setClientPrincipal( tgt.getEncTicketPart().getClientPrincipal() );
+
+        if ( request.getEncAuthorizationData() != null )
+        {
+            AuthorizationData authData = ( AuthorizationData ) cipherTextHandler.unseal( AuthorizationData.class,
+                authenticator.getSubSessionKey(), request.getEncAuthorizationData(), KeyUsage.NUMBER4 );
+            authData.add( tgt.getEncTicketPart().getAuthorizationData() );
+            newTicketBody.setAuthorizationData( authData );
+        }
+
+        processTransited( newTicketBody, tgt );
+
+        processTimes( config, request, newTicketBody, tgt );
+
+        EncTicketPart ticketPart = newTicketBody.getEncTicketPart();
+
+        if ( request.getOption( KdcOptions.ENC_TKT_IN_SKEY ) )
+        {
+            /*
+             * if (server not specified) then
+             *         server = req.second_ticket.client;
+             * endif
+             * 
+             * if ((req.second_ticket is not a TGT) or
+             *     (req.second_ticket.client != server)) then
+             *         error_out(KDC_ERR_POLICY);
+             * endif
+             * 
+             * new_tkt.enc-part := encrypt OCTET STRING using etype_for_key(second-ticket.key), second-ticket.key;
+             */   
+    
+            throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+        }
+        else
+        {
+            EncryptedData encryptedData = cipherTextHandler.seal( serverKey, ticketPart, KeyUsage.NUMBER2 );
+
+            Ticket newTicket = new Ticket( ticketPrincipal, encryptedData );
+            newTicket.setEncTicketPart( ticketPart );
+
+            tgsContext.setNewTicket( newTicket );
+        }
+    }
+    
+
+    private static void buildReply( TicketGrantingContext tgsContext, IoSession sessione ) throws KerberosException
+    {
+        KdcRequest request = tgsContext.getRequest();
+        Ticket tgt = tgsContext.getTgt();
+        Ticket newTicket = tgsContext.getNewTicket();
+
+        TicketGrantReply reply = new TicketGrantReply();
+        reply.setClientPrincipal( tgt.getEncTicketPart().getClientPrincipal() );
+        reply.setTicket( newTicket );
+        reply.setKey( newTicket.getEncTicketPart().getSessionKey() );
+        reply.setNonce( request.getNonce() );
+        // TODO - resp.last-req := fetch_last_request_info(client); requires store
+        reply.setLastRequest( new LastRequest() );
+        reply.setFlags( newTicket.getEncTicketPart().getFlags() );
+        reply.setClientAddresses( newTicket.getEncTicketPart().getClientAddresses() );
+        reply.setAuthTime( newTicket.getEncTicketPart().getAuthTime() );
+        reply.setStartTime( newTicket.getEncTicketPart().getStartTime() );
+        reply.setEndTime( newTicket.getEncTicketPart().getEndTime() );
+        reply.setServerPrincipal( newTicket.getServerPrincipal() );
+
+        if ( newTicket.getEncTicketPart().getFlags().get( TicketFlags.RENEWABLE ) )
+        {
+            reply.setRenewTill( newTicket.getEncTicketPart().getRenewTill() );
+        }
+
+        tgsContext.setReply( reply );
+    }
+    
+    
+    private static void sealReply( TicketGrantingContext tgsContext, IoSession session ) throws KerberosException
+    {
+        TicketGrantReply reply = ( TicketGrantReply ) tgsContext.getReply();
+        Ticket tgt = tgsContext.getTgt();
+        CipherTextHandler cipherTextHandler = tgsContext.getCipherTextHandler();
+        Authenticator authenticator = tgsContext.getAuthenticator();
+
+        EncryptedData encryptedData;
+
+        if ( authenticator.getSubSessionKey() != null )
+        {
+            encryptedData = cipherTextHandler.seal( authenticator.getSubSessionKey(), reply, KeyUsage.NUMBER9 );
+        }
+        else
+        {
+            encryptedData = cipherTextHandler.seal( tgt.getEncTicketPart().getSessionKey(), reply, KeyUsage.NUMBER8 );
+        }
+
+        reply.setEncPart( encryptedData );
+    }
+    
+    
+    
+    private static void monitorContext( TicketGrantingContext tgsContext )
+    {
+        try
+        {
+            Ticket tgt = tgsContext.getTgt();
+            long clockSkew = tgsContext.getConfig().getAllowableClockSkew();
+            ChecksumType checksumType = tgsContext.getAuthenticator().getChecksum().getChecksumType();
+            InetAddress clientAddress = tgsContext.getClientAddress();
+            HostAddresses clientAddresses = tgt.getEncTicketPart().getClientAddresses();
+
+            boolean caddrContainsSender = false;
+            
+            if ( tgt.getEncTicketPart().getClientAddresses() != null )
+            {
+                caddrContainsSender = tgt.getEncTicketPart().getClientAddresses().contains( new HostAddress( clientAddress ) );
+            }
+
+            StringBuffer sb = new StringBuffer();
+
+            sb.append( "Monitoring " + SERVICE_NAME + " context:" );
+
+            sb.append( "\n\t" + "clockSkew              " + clockSkew );
+            sb.append( "\n\t" + "checksumType           " + checksumType );
+            sb.append( "\n\t" + "clientAddress          " + clientAddress );
+            sb.append( "\n\t" + "clientAddresses        " + clientAddresses );
+            sb.append( "\n\t" + "caddr contains sender  " + caddrContainsSender );
+
+            KerberosPrincipal requestServerPrincipal = tgsContext.getRequest().getServerPrincipal();
+            PrincipalStoreEntry requestPrincipal = tgsContext.getRequestPrincipalEntry();
+
+            sb.append( "\n\t" + "principal              " + requestServerPrincipal );
+            sb.append( "\n\t" + "cn                     " + requestPrincipal.getCommonName() );
+            sb.append( "\n\t" + "realm                  " + requestPrincipal.getRealmName() );
+            sb.append( "\n\t" + "principal              " + requestPrincipal.getPrincipal() );
+            sb.append( "\n\t" + "SAM type               " + requestPrincipal.getSamType() );
+
+            KerberosPrincipal ticketServerPrincipal = tgsContext.getTgt().getServerPrincipal();
+            PrincipalStoreEntry ticketPrincipal = tgsContext.getTicketPrincipalEntry();
+
+            sb.append( "\n\t" + "principal              " + ticketServerPrincipal );
+            sb.append( "\n\t" + "cn                     " + ticketPrincipal.getCommonName() );
+            sb.append( "\n\t" + "realm                  " + ticketPrincipal.getRealmName() );
+            sb.append( "\n\t" + "principal              " + ticketPrincipal.getPrincipal() );
+            sb.append( "\n\t" + "SAM type               " + ticketPrincipal.getSamType() );
+
+            EncryptionType encryptionType = tgsContext.getTgt().getEncPart().getEType();
+            int keyVersion = ticketPrincipal.getKeyMap().get( encryptionType ).getKeyVersion();
+            sb.append( "\n\t" + "Ticket key type        " + encryptionType );
+            sb.append( "\n\t" + "Service key version    " + keyVersion );
+
+            LOG.debug( sb.toString() );
+        }
+        catch ( Exception e )
+        {
+            // This is a monitor.  No exceptions should bubble up.
+            LOG.error( "Error in context monitor", e );
+        }
+    }
+
+    
+    private static void monitorReply( IoSession session )
+    {
+        KdcContext kdcContext = ( KdcContext ) session.getAttribute( CONTEXT_KEY );
+        Object reply = kdcContext.getReply();
+
+        if ( reply instanceof KdcReply )
+        {
+            KdcReply success = ( KdcReply ) reply;
+
+            try
+            {
+                StringBuffer sb = new StringBuffer();
+
+                sb.append( "Responding with " + SERVICE_NAME + " reply:" );
+                sb.append( "\n\t" + "messageType:           " + success.getMessageType() );
+                sb.append( "\n\t" + "protocolVersionNumber: " + success.getProtocolVersionNumber() );
+                sb.append( "\n\t" + "nonce:                 " + success.getNonce() );
+                sb.append( "\n\t" + "clientPrincipal:       " + success.getClientPrincipal() );
+                sb.append( "\n\t" + "client realm:          " + success.getClientRealm() );
+                sb.append( "\n\t" + "serverPrincipal:       " + success.getServerPrincipal() );
+                sb.append( "\n\t" + "server realm:          " + success.getServerRealm() );
+                sb.append( "\n\t" + "auth time:             " + success.getAuthTime() );
+                sb.append( "\n\t" + "start time:            " + success.getStartTime() );
+                sb.append( "\n\t" + "end time:              " + success.getEndTime() );
+                sb.append( "\n\t" + "renew-till time:       " + success.getRenewTill() );
+                sb.append( "\n\t" + "hostAddresses:         " + success.getClientAddresses() );
+
+                LOG.debug( sb.toString() );
+            }
+            catch ( Exception e )
+            {
+                // This is a monitor.  No exceptions should bubble up.
+                LOG.error( "Error in reply monitor", e );
+            }
+        }
+    }
+    
+
+    
+    private static void processFlags( KdcServer config, KdcRequest request, Ticket tgt,
+        EncTicketPartModifier newTicketBody ) throws KerberosException
+    {
+        if ( tgt.getEncTicketPart().getFlags().get( TicketFlags.PRE_AUTHENT ) )
+        {
+            newTicketBody.setFlag( TicketFlag.PRE_AUTHENT.getOrdinal() );
+        }
+
+        if ( request.getOption( KdcOptions.FORWARDABLE ) )
+        {
+            if ( !config.isForwardableAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.FORWARDABLE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            newTicketBody.setFlag( TicketFlag.FORWARDABLE.getOrdinal() );
+        }
+
+        if ( request.getOption( KdcOptions.FORWARDED ) )
+        {
+            if ( !config.isForwardableAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.FORWARDABLE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            if ( request.getAddresses() != null && request.getAddresses().getAddresses() != null
+                && request.getAddresses().getAddresses().length > 0 )
+            {
+                newTicketBody.setClientAddresses( request.getAddresses() );
+            }
+            else
+            {
+                if ( !config.isEmptyAddressesAllowed() )
+                {
+                    throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+                }
+            }
+
+            newTicketBody.setFlag( TicketFlag.FORWARDED.getOrdinal() );
+        }
+
+        if ( tgt.getEncTicketPart().getFlags().get( TicketFlags.FORWARDED ) )
+        {
+            newTicketBody.setFlag( TicketFlag.FORWARDED.getOrdinal() );
+        }
+
+        if ( request.getOption( KdcOptions.PROXIABLE ) )
+        {
+            if ( !config.isProxiableAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.PROXIABLE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            newTicketBody.setFlag( TicketFlag.PROXIABLE.getOrdinal() );
+        }
+
+        if ( request.getOption( KdcOptions.PROXY ) )
+        {
+            if ( !config.isProxiableAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.PROXIABLE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            if ( request.getAddresses() != null && request.getAddresses().getAddresses() != null
+                && request.getAddresses().getAddresses().length > 0 )
+            {
+                newTicketBody.setClientAddresses( request.getAddresses() );
+            }
+            else
+            {
+                if ( !config.isEmptyAddressesAllowed() )
+                {
+                    throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+                }
+            }
+
+            newTicketBody.setFlag( TicketFlag.PROXY.getOrdinal() );
+        }
+
+        if ( request.getOption( KdcOptions.ALLOW_POSTDATE ) )
+        {
+            if ( !config.isPostdatedAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.MAY_POSTDATE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            newTicketBody.setFlag( TicketFlag.MAY_POSTDATE.getOrdinal() );
+        }
+
+        /*
+         * "Otherwise, if the TGT has the MAY-POSTDATE flag set, then the resulting
+         * ticket will be postdated, and the requested starttime is checked against
+         * the policy of the local realm.  If acceptable, the ticket's starttime is
+         * set as requested, and the INVALID flag is set.  The postdated ticket MUST
+         * be validated before use by presenting it to the KDC after the starttime
+         * has been reached.  However, in no case may the starttime, endtime, or
+         * renew-till time of a newly-issued postdated ticket extend beyond the
+         * renew-till time of the TGT."
+         */        
+        if ( request.getOption( KdcOptions.POSTDATED ) )
+        {
+            if ( !config.isPostdatedAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.MAY_POSTDATE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            newTicketBody.setFlag( TicketFlag.POSTDATED.getOrdinal() );
+            newTicketBody.setFlag( TicketFlag.INVALID.getOrdinal() );
+
+            newTicketBody.setStartTime( request.getFrom() );
+        }
+
+        if ( request.getOption( KdcOptions.VALIDATE ) )
+        {
+            if ( !config.isPostdatedAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.INVALID ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            KerberosTime startTime = ( tgt.getEncTicketPart().getStartTime() != null ) ? 
+                    tgt.getEncTicketPart().getStartTime() : 
+                        tgt.getEncTicketPart().getAuthTime();
+
+            if ( startTime.greaterThan( new KerberosTime() ) )
+            {
+                throw new KerberosException( ErrorType.KRB_AP_ERR_TKT_NYV );
+            }
+
+            echoTicket( newTicketBody, tgt );
+            newTicketBody.clearFlag( TicketFlag.INVALID.getOrdinal() );
+        }
+
+        if ( request.getOption( KdcOptions.RESERVED ) )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+        }
+    }
+
+
+    private static void processTimes( KdcServer config, KdcRequest request, EncTicketPartModifier newTicketBody,
+        Ticket tgt ) throws KerberosException
+    {
+        KerberosTime now = new KerberosTime();
+
+        newTicketBody.setAuthTime( tgt.getEncTicketPart().getAuthTime() );
+
+        KerberosTime startTime = request.getFrom();
+
+        /*
+         * "If the requested starttime is absent, indicates a time in the past,
+         * or is within the window of acceptable clock skew for the KDC and the
+         * POSTDATE option has not been specified, then the starttime of the
+         * ticket is set to the authentication server's current time."
+         */        
+        if ( startTime == null || startTime.lessThan( now ) || startTime.isInClockSkew( config.getAllowableClockSkew() )
+            && !request.getOption( KdcOptions.POSTDATED ) )
+        {
+            startTime = now;
+        }
+
+        /*
+         * "If it indicates a time in the future beyond the acceptable clock skew,
+         * but the POSTDATED option has not been specified or the MAY-POSTDATE flag
+         * is not set in the TGT, then the error KDC_ERR_CANNOT_POSTDATE is
+         * returned."
+         */        
+        if ( startTime != null && startTime.greaterThan( now )
+            && !startTime.isInClockSkew( config.getAllowableClockSkew() )
+            && ( !request.getOption( KdcOptions.POSTDATED ) || !tgt.getEncTicketPart().getFlags().get( TicketFlags.MAY_POSTDATE ) ) )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_CANNOT_POSTDATE );
+        }
+
+        KerberosTime renewalTime = null;
+        KerberosTime kerberosEndTime = null;
+
+        if ( request.getOption( KdcOptions.RENEW ) )
+        {
+            if ( !config.isRenewableAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            if ( !tgt.getEncTicketPart().getFlags().get( TicketFlags.RENEWABLE ) )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_BADOPTION );
+            }
+
+            if ( tgt.getEncTicketPart().getRenewTill().lessThan( now ) )
+            {
+                throw new KerberosException( ErrorType.KRB_AP_ERR_TKT_EXPIRED );
+            }
+
+            echoTicket( newTicketBody, tgt );
+
+            newTicketBody.setStartTime( now );
+
+            KerberosTime tgtStartTime = ( tgt.getEncTicketPart().getStartTime() != null ) ? 
+                tgt.getEncTicketPart().getStartTime() : 
+                    tgt.getEncTicketPart().getAuthTime();
+
+            long oldLife = tgt.getEncTicketPart().getEndTime().getTime() - tgtStartTime.getTime();
+
+            kerberosEndTime = new KerberosTime( Math.min( tgt.getEncTicketPart().getRenewTill().getTime(), now.getTime() + oldLife ) );
+            newTicketBody.setEndTime( kerberosEndTime );
+        }
+        else
+        {
+            if ( newTicketBody.getEncTicketPart().getStartTime() == null )
+            {
+                newTicketBody.setStartTime( now );
+            }
+
+            KerberosTime till;
+            if ( request.getTill().isZero() )
+            {
+                till = KerberosTime.INFINITY;
+            }
+            else
+            {
+                till = request.getTill();
+            }
+
+            /*
+             * The end time is the minimum of (a) the requested till time or (b)
+             * the start time plus maximum lifetime as configured in policy or (c)
+             * the end time of the TGT.
+             */  
+            List<KerberosTime> minimizer = new ArrayList<KerberosTime>();
+            minimizer.add( till );
+            minimizer.add( new KerberosTime( startTime.getTime() + config.getMaximumTicketLifetime() ) );
+            minimizer.add( tgt.getEncTicketPart().getEndTime() );
+            kerberosEndTime = Collections.min( minimizer );
+
+            newTicketBody.setEndTime( kerberosEndTime );
+
+            if ( request.getOption( KdcOptions.RENEWABLE_OK ) && kerberosEndTime.lessThan( request.getTill() )
+                && tgt.getEncTicketPart().getFlags().get( TicketFlags.RENEWABLE ) )
+            {
+                if ( !config.isRenewableAllowed() )
+                {
+                    throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+                }
+
+                // We set the RENEWABLE option for later processing.                           
+                request.setOption( KdcOptions.RENEWABLE );
+                long rtime = Math.min( request.getTill().getTime(), tgt.getEncTicketPart().getRenewTill().getTime() );
+                renewalTime = new KerberosTime( rtime );
+            }
+        }
+
+        if ( renewalTime == null )
+        {
+            renewalTime = request.getRtime();
+        }
+
+        KerberosTime rtime;
+        if ( renewalTime != null && renewalTime.isZero() )
+        {
+            rtime = KerberosTime.INFINITY;
+        }
+        else
+        {
+            rtime = renewalTime;
+        }
+
+        if ( request.getOption( KdcOptions.RENEWABLE ) && tgt.getEncTicketPart().getFlags().get( TicketFlags.RENEWABLE ) )
+        {
+            if ( !config.isRenewableAllowed() )
+            {
+                throw new KerberosException( ErrorType.KDC_ERR_POLICY );
+            }
+
+            newTicketBody.setFlag( TicketFlag.RENEWABLE.getOrdinal() );
+
+            /*
+             * The renew-till time is the minimum of (a) the requested renew-till
+             * time or (b) the start time plus maximum renewable lifetime as
+             * configured in policy or (c) the renew-till time of the TGT.
+             */        
+            List<KerberosTime> minimizer = new ArrayList<KerberosTime>();
+
+            /*
+             * 'rtime' KerberosTime is OPTIONAL
+             */        
+            if ( rtime != null )
+            {
+                minimizer.add( rtime );
+            }
+
+            minimizer.add( new KerberosTime( startTime.getTime() + config.getMaximumRenewableLifetime() ) );
+            minimizer.add( tgt.getEncTicketPart().getRenewTill() );
+            newTicketBody.setRenewTill( Collections.min( minimizer ) );
+        }
+
+        /*
+         * "If the requested expiration time minus the starttime (as determined
+         * above) is less than a site-determined minimum lifetime, an error
+         * message with code KDC_ERR_NEVER_VALID is returned."
+         */        
+        if ( kerberosEndTime.lessThan( startTime ) )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_NEVER_VALID );
+        }
+
+        long ticketLifeTime = Math.abs( startTime.getTime() - kerberosEndTime.getTime() );
+        if ( ticketLifeTime < config.getAllowableClockSkew() )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_NEVER_VALID );
+        }
+    }
+
+
+    /*
+     * if (realm_tgt_is_for(tgt) := tgt.realm) then
+     *         // tgt issued by local realm
+     *         new_tkt.transited := tgt.transited;
+     * else
+     *         // was issued for this realm by some other realm
+     *         if (tgt.transited.tr-type not supported) then
+     *                 error_out(KDC_ERR_TRTYPE_NOSUPP);
+     *         endif
+     * 
+     *         new_tkt.transited := compress_transited(tgt.transited + tgt.realm)
+     * endif
+     */    
+    private static void processTransited( EncTicketPartModifier newTicketBody, Ticket tgt )
+    {
+        // TODO - currently no transited support other than local
+        newTicketBody.setTransitedEncoding( tgt.getEncTicketPart().getTransitedEncoding() );
+    }
+
+    
+    private static void echoTicket( EncTicketPartModifier newTicketBody, Ticket tgt )
+    {
+        EncTicketPart encTicketpart = tgt.getEncTicketPart();
+        newTicketBody.setAuthorizationData( encTicketpart.getAuthorizationData() );
+        newTicketBody.setAuthTime( encTicketpart.getAuthTime() );
+        newTicketBody.setClientAddresses( encTicketpart.getClientAddresses() );
+        newTicketBody.setClientPrincipal( encTicketpart.getClientPrincipal() );
+        newTicketBody.setEndTime( encTicketpart.getEndTime() );
+        newTicketBody.setFlags( encTicketpart.getFlags() );
+        newTicketBody.setRenewTill( encTicketpart.getRenewTill() );
+        newTicketBody.setSessionKey( encTicketpart.getSessionKey() );
+        newTicketBody.setTransitedEncoding( encTicketpart.getTransitedEncoding() );
+    }
+    
+    private static ApplicationRequest getAuthHeader( KdcRequest request ) throws KerberosException, IOException
+    {
+        PaData[] preAuthData = request.getPreAuthData();
+
+        if ( preAuthData == null || preAuthData.length < 1 )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_PADATA_TYPE_NOSUPP );
+        }
+
+        byte[] undecodedAuthHeader = null;
+
+        for ( int ii = 0; ii < preAuthData.length; ii++ )
+        {
+            if ( preAuthData[ii].getPaDataType() == PaDataType.PA_TGS_REQ )
+            {
+                undecodedAuthHeader = preAuthData[ii].getPaDataValue();
+            }
+        }
+
+        if ( undecodedAuthHeader == null )
+        {
+            throw new KerberosException( ErrorType.KDC_ERR_PADATA_TYPE_NOSUPP );
+        }
+
+        ApplicationRequestDecoder decoder = new ApplicationRequestDecoder();
+        ApplicationRequest authHeader = decoder.decode( undecodedAuthHeader );
+
+        return authHeader;
+    }
+    
+
+    /**
+     * Find the best encryption type, comparing the requested type with
+     * configured types.
+     */    
+    protected static EncryptionType getBestEncryptionType( EncryptionType[] requestedTypes, EncryptionType[] configuredTypes )
+    {
+        for ( EncryptionType requestedType:requestedTypes )
+        {
+            for ( EncryptionType configuredType:configuredTypes )
+            {
+                if ( requestedType == configuredType )
+                {
+                    return configuredType;
+                }
+            }
+        }
+
+        return null;
+    }
+}

Modified: directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/VerifyTgtAuthHeader.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/VerifyTgtAuthHeader.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/VerifyTgtAuthHeader.java (original)
+++ directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/kdc/ticketgrant/VerifyTgtAuthHeader.java Wed Oct 31 13:37:23 2007
@@ -22,6 +22,7 @@
 
 import java.net.InetAddress;
 
+import org.apache.directory.server.kerberos.shared.KerberosUtils;
 import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
 import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
 import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
@@ -31,16 +32,18 @@
 import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
 import org.apache.directory.server.kerberos.shared.messages.value.KdcOptions;
 import org.apache.directory.server.kerberos.shared.replay.ReplayCache;
-import org.apache.directory.server.kerberos.shared.service.VerifyAuthHeader;
 import org.apache.mina.common.IoSession;
+import org.apache.mina.handler.chain.IoHandlerCommand;
 
 
 /**
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  * @version $Rev$, $Date$
  */
-public class VerifyTgtAuthHeader extends VerifyAuthHeader
+public class VerifyTgtAuthHeader implements IoHandlerCommand
 {
+    private String contextKey = "context";
+
     public void execute( NextCommand next, IoSession session, Object message ) throws Exception
     {
         TicketGrantingContext tgsContext = ( TicketGrantingContext ) session.getAttribute( getContextKey() );
@@ -59,11 +62,17 @@
         InetAddress clientAddress = tgsContext.getClientAddress();
         CipherTextHandler cipherTextHandler = tgsContext.getCipherTextHandler();
 
-        Authenticator authenticator = verifyAuthHeader( authHeader, tgt, serverKey, clockSkew, replayCache,
+        Authenticator authenticator = KerberosUtils.verifyAuthHeader( authHeader, tgt, serverKey, clockSkew, replayCache,
             emptyAddressesAllowed, clientAddress, cipherTextHandler, KeyUsage.NUMBER7, isValidate );
 
         tgsContext.setAuthenticator( authenticator );
 
         next.execute( session, message );
+    }
+
+
+    protected String getContextKey()
+    {
+        return ( this.contextKey );
     }
 }

Modified: directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/protocol/KerberosProtocolHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/protocol/KerberosProtocolHandler.java?rev=590816&r1=590815&r2=590816&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/protocol/KerberosProtocolHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-kerberos/src/main/java/org/apache/directory/server/kerberos/protocol/KerberosProtocolHandler.java Wed Oct 31 13:37:23 2007
@@ -29,6 +29,7 @@
 import org.apache.directory.server.kerberos.kdc.authentication.AuthenticationContext;
 import org.apache.directory.server.kerberos.kdc.authentication.AuthenticationService;
 import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingContext;
+import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingService;
 import org.apache.directory.server.kerberos.kdc.ticketgrant.TicketGrantingServiceChain;
 import org.apache.directory.server.kerberos.shared.KerberosMessageType;
 import org.apache.directory.server.kerberos.shared.exceptions.ErrorType;
@@ -171,7 +172,7 @@
                     tgsContext.setRequest( request );
                     session.setAttribute( getContextKey(), tgsContext );
 
-                    //TgsService.execute( session, tgsContext );
+                    //TicketGrantingService.execute( session, tgsContext );
                     tgsService.execute( null, session, message );
 
                     session.write( tgsContext.getReply() );