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() );