View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.kerberos.client;
21  
22  
23  import java.io.IOException;
24  import java.nio.ByteBuffer;
25  import java.security.SecureRandom;
26  import java.text.ParseException;
27  import java.util.List;
28  
29  import javax.security.auth.kerberos.KerberosPrincipal;
30  
31  import org.apache.directory.api.asn1.Asn1Object;
32  import org.apache.directory.api.util.Network;
33  import org.apache.directory.api.util.Strings;
34  import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
35  import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
36  import org.apache.directory.server.kerberos.changepwd.io.ChangePasswordDecoder;
37  import org.apache.directory.server.kerberos.changepwd.io.ChangePasswordEncoder;
38  import org.apache.directory.server.kerberos.changepwd.messages.AbstractPasswordMessage;
39  import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordError;
40  import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordReply;
41  import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordRequest;
42  import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler;
43  import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory;
44  import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage;
45  import org.apache.directory.server.kerberos.shared.crypto.encryption.RandomKeyFactory;
46  import org.apache.directory.shared.kerberos.KerberosTime;
47  import org.apache.directory.shared.kerberos.codec.KerberosDecoder;
48  import org.apache.directory.shared.kerberos.codec.KerberosEncoder;
49  import org.apache.directory.shared.kerberos.codec.KerberosMessageContainer;
50  import org.apache.directory.shared.kerberos.codec.options.ApOptions;
51  import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
52  import org.apache.directory.shared.kerberos.codec.types.PaDataType;
53  import org.apache.directory.shared.kerberos.codec.types.PrincipalNameType;
54  import org.apache.directory.shared.kerberos.components.EncKdcRepPart;
55  import org.apache.directory.shared.kerberos.components.EncKrbPrivPart;
56  import org.apache.directory.shared.kerberos.components.EncryptedData;
57  import org.apache.directory.shared.kerberos.components.EncryptionKey;
58  import org.apache.directory.shared.kerberos.components.HostAddress;
59  import org.apache.directory.shared.kerberos.components.HostAddresses;
60  import org.apache.directory.shared.kerberos.components.KdcReqBody;
61  import org.apache.directory.shared.kerberos.components.PaData;
62  import org.apache.directory.shared.kerberos.components.PaEncTsEnc;
63  import org.apache.directory.shared.kerberos.components.PrincipalName;
64  import org.apache.directory.shared.kerberos.exceptions.ErrorType;
65  import org.apache.directory.shared.kerberos.exceptions.KerberosException;
66  import org.apache.directory.shared.kerberos.messages.ApReq;
67  import org.apache.directory.shared.kerberos.messages.AsRep;
68  import org.apache.directory.shared.kerberos.messages.AsReq;
69  import org.apache.directory.shared.kerberos.messages.Authenticator;
70  import org.apache.directory.shared.kerberos.messages.ChangePasswdData;
71  import org.apache.directory.shared.kerberos.messages.EncAsRepPart;
72  import org.apache.directory.shared.kerberos.messages.EncTgsRepPart;
73  import org.apache.directory.shared.kerberos.messages.KerberosMessage;
74  import org.apache.directory.shared.kerberos.messages.KrbError;
75  import org.apache.directory.shared.kerberos.messages.KrbPriv;
76  import org.apache.directory.shared.kerberos.messages.TgsRep;
77  import org.apache.directory.shared.kerberos.messages.TgsReq;
78  import org.slf4j.Logger;
79  import org.slf4j.LoggerFactory;
80  
81  
82  /**
83   * 
84   * A client to connect to kerberos servers using TCP or UDP transports.
85   * 
86   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
87   */
88  public class KdcConnection
89  {
90  
91      private static final Logger LOG = LoggerFactory.getLogger( KdcConnection.class );
92  
93      /** a secure random number generator used for creating nonces */
94      private SecureRandom nonceGenerator;
95  
96      static final String TIME_OUT_ERROR = "TimeOut occured";
97  
98      /** the cipher text handler */
99      private CipherTextHandler cipherTextHandler;
100 
101     /** underlying network channel handler */
102     private KerberosChannel channel;
103 
104     private KdcConfig config;
105 
106 
107     /**
108      * 
109      * Creates a new instance of KdcConnection.
110      *
111      * @param config the configuration of KDC
112      */
113     public KdcConnection( KdcConfig config )
114     {
115         this.config = config;
116 
117         nonceGenerator = new SecureRandom(
118             Strings.getBytesUtf8( String.valueOf( System.currentTimeMillis() ) ) );
119         cipherTextHandler = new CipherTextHandler();
120         channel = new KerberosChannel();
121     }
122 
123 
124     private void connect() throws IOException
125     {
126         channel.openConnection( config.getHostName(), config.getKdcPort(), config.getTimeout(), config.isUseUdp() );
127     }
128 
129 
130     /**
131      * Authenticates to the Kerberos server and gets the initial Ticket Granting Ticket
132      * 
133      * @param principal the client's principal 
134      * @param password password of the client
135      * @return A Ticket Granting Ticket instance
136      * @throws KerberosException If a Ticket Granting Ticket cannot be fetch
137      */
138     public TgTicket getTgt( String principal, String password ) throws KerberosException
139     {
140         TgtRequestt/TgtRequest.html#TgtRequest">TgtRequest clientTgtReq = new TgtRequest();
141 
142         clientTgtReq.setClientPrincipal( principal );
143         clientTgtReq.setPassword( password );
144 
145         return getTgt( clientTgtReq );
146     }
147 
148 
149     /**
150      * Authenticates to the Kerberos server and gets a service ticket for the given server principal
151      * 
152      * @param clientPrincipal the client's principal 
153      * @param password password of the client
154      * @param serverPrincipal the application server's principal
155      * @return A ServiceTicket instance
156      * @throws KerberosException If the ServiceTicket cannot be fetch
157      */
158     public ServiceTicket getServiceTicket( String clientPrincipal, String password, String serverPrincipal )
159         throws KerberosException
160     {
161         TgtRequestt/TgtRequest.html#TgtRequest">TgtRequest clientTgtReq = new TgtRequest();
162         clientTgtReq.setClientPrincipal( clientPrincipal );
163         clientTgtReq.setPassword( password );
164 
165         TgTicket tgt = getTgt( clientTgtReq );
166 
167         return getServiceTicket( new ServiceTicketRequest( tgt, serverPrincipal ) );
168     }
169 
170 
171     public TgTicket getTgt( TgtRequest clientTgtReq ) throws KerberosException
172     {
173         TgTicket tgt = null;
174 
175         KerberosException ke = null;
176 
177         for ( int i = 0; i < 2; i++ )
178         {
179             ke = null;
180 
181             try
182             {
183                 tgt = _getTgt( clientTgtReq );
184             }
185             catch ( KerberosException e )
186             {
187                 // using exception for control flow, b.a.d, but here it is better than
188                 // defining a new Result class to hold ticket and exception and validating
189                 // the Result instance from _getTgt()
190                 ke = e;
191             }
192 
193             if ( ( ke != null ) && ( ke.getErrorCode() == ErrorType.KDC_ERR_PREAUTH_REQUIRED.getValue() ) )
194             {
195                 clientTgtReq.setETypes( KdcClientUtil.getEtypesFromError( ke.getError() ) );
196                 clientTgtReq.setPreAuthEnabled( true );
197             }
198         }
199 
200         if ( ke != null )
201         {
202             throw ke;
203         }
204 
205         return tgt;
206     }
207 
208 
209     /* default protected */ TgTicket _getTgt( TgtRequest clientTgtReq ) throws KerberosException
210     {
211         String realm = clientTgtReq.getRealm();
212 
213         if ( clientTgtReq.getServerPrincipal() == null )
214         {
215             String serverPrincipal = "krbtgt/" + realm + "@" + realm;
216             clientTgtReq.setServerPrincipal( serverPrincipal );
217         }
218 
219         if ( clientTgtReq.getETypes() == null )
220         {
221             clientTgtReq.setETypes( config.getEncryptionTypes() );
222         }
223 
224         KdcReqBody/kerberos/components/KdcReqBody.html#KdcReqBody">KdcReqBody body = new KdcReqBody();
225 
226         body.setFrom( new KerberosTime( clientTgtReq.getStartTime() ) );
227 
228         PrincipalName cName = null;
229         try
230         {
231             cName = new PrincipalName( clientTgtReq.getCName(), PrincipalNameType.KRB_NT_PRINCIPAL );
232             body.setCName( cName );
233             body.setRealm( realm );
234             PrincipalNameberos/components/PrincipalName.html#PrincipalName">PrincipalName sName = new PrincipalName( clientTgtReq.getSName(), PrincipalNameType.KRB_NT_SRV_INST );
235             body.setSName( sName );
236         }
237         catch ( ParseException e )
238         {
239             throw new IllegalArgumentException( "Couldn't parse the given principals", e );
240         }
241 
242         body.setTill( new KerberosTime( clientTgtReq.getExpiryTime() ) );
243         int currentNonce = nonceGenerator.nextInt();
244         body.setNonce( currentNonce );
245         body.setEType( clientTgtReq.getETypes() );
246         body.setKdcOptions( clientTgtReq.getOptions() );
247 
248         List<HostAddress> lstAddresses = clientTgtReq.getHostAddresses();
249         if ( !lstAddresses.isEmpty() )
250         {
251             HostAddressess/components/HostAddresses.html#HostAddresses">HostAddresses addresses = new HostAddresses();
252             for ( HostAddress h : lstAddresses )
253             {
254                 addresses.addHostAddress( h );
255             }
256 
257             body.setAddresses( addresses );
258         }
259 
260         EncryptionType encryptionType = clientTgtReq.getETypes().iterator().next();
261         EncryptionKey clientKey = KerberosKeyFactory.string2Key( clientTgtReq.getClientPrincipal(),
262             clientTgtReq.getPassword(), encryptionType );
263 
264         AsReqshared/kerberos/messages/AsReq.html#AsReq">AsReq req = new AsReq();
265         req.setKdcReqBody( body );
266 
267         if ( clientTgtReq.isPreAuthEnabled() )
268         {
269             PaEncTsEncerberos/components/PaEncTsEnc.html#PaEncTsEnc">PaEncTsEnc tmstmp = new PaEncTsEnc();
270             tmstmp.setPaTimestamp( new KerberosTime() );
271 
272             EncryptedData paDataValue = cipherTextHandler.encrypt( clientKey, getEncoded( tmstmp ),
273                 KeyUsage.AS_REQ_PA_ENC_TIMESTAMP_WITH_CKEY );
274 
275             PaDataerberos/components/PaData.html#PaData">PaData paEncTstmp = new PaData();
276             paEncTstmp.setPaDataType( PaDataType.PA_ENC_TIMESTAMP );
277             paEncTstmp.setPaDataValue( getEncoded( paDataValue ) );
278 
279             req.addPaData( paEncTstmp );
280         }
281 
282         // Get the result from the future
283         try
284         {
285             connect();
286 
287             // Read the response, waiting for it if not available immediately
288             // Get the response, blocking
289             KerberosMessage kdcRep = sendAndReceiveKrbMsg( req );
290 
291             if ( kdcRep == null )
292             {
293                 // We didn't received anything : this is an error
294                 LOG.error( "Authentication failed : timeout occured" );
295                 throw new KerberosException( ErrorType.KRB_ERR_GENERIC, TIME_OUT_ERROR );
296             }
297 
298             if ( kdcRep instanceof KrbError )
299             {
300                 // We have an error
301                 LOG.debug( "Authentication failed : {}", kdcRep );
302                 throw new KerberosException( ( KrbError ) kdcRep );
303             }
304 
305             AsRepf="../../../../../org/apache/directory/shared/kerberos/messages/AsRep.html#AsRep">AsRep rep = ( AsRep ) kdcRep;
306 
307             if ( !cName.getNameString().equals( rep.getCName().getNameString() ) )
308             {
309                 throw new KerberosException( ErrorType.KDC_ERR_CLIENT_NAME_MISMATCH );
310             }
311 
312             if ( !realm.equals( rep.getCRealm() ) )
313             {
314                 throw new KerberosException( ErrorType.KRB_ERR_WRONG_REALM );
315             }
316 
317             if ( encryptionType != rep.getEncPart().getEType() )
318             {
319                 encryptionType = rep.getEncPart().getEType();
320                 clientKey = KerberosKeyFactory.string2Key( clientTgtReq.getClientPrincipal(),
321                     clientTgtReq.getPassword(), encryptionType );
322             }
323 
324             byte[] decryptedEncAsRepPart = cipherTextHandler.decrypt( clientKey, rep.getEncPart(),
325                 KeyUsage.AS_REP_ENC_PART_WITH_CKEY );
326 
327             EncKdcRepPart encKdcRepPart = null;
328             try
329             {
330                 EncAsRepPart encAsRepPart = KerberosDecoder.decodeEncAsRepPart( decryptedEncAsRepPart );
331                 encKdcRepPart = encAsRepPart.getEncKdcRepPart();
332             }
333             catch ( KerberosException e )
334             {
335                 LOG.info( "Trying an encTgsRepPart instead" );
336                 EncTgsRepPart encTgsRepPart = KerberosDecoder.decodeEncTgsRepPart( decryptedEncAsRepPart );
337                 encKdcRepPart = encTgsRepPart.getEncKdcRepPart();
338             }
339 
340             if ( currentNonce != encKdcRepPart.getNonce() )
341             {
342                 throw new KerberosException( ErrorType.KRB_ERR_GENERIC,
343                     "received nonce didn't match with the nonce sent in the request" );
344             }
345 
346             if ( !encKdcRepPart.getSName().getNameString().equals( clientTgtReq.getSName() ) )
347             {
348                 throw new KerberosException( ErrorType.KDC_ERR_SERVER_NOMATCH );
349             }
350 
351             if ( !encKdcRepPart.getSRealm().equals( clientTgtReq.getRealm() ) )
352             {
353                 throw new KerberosException( ErrorType.KRB_ERR_GENERIC,
354                     "received server realm does not match with requested server realm" );
355             }
356 
357             List<HostAddress> hosts = clientTgtReq.getHostAddresses();
358 
359             if ( !hosts.isEmpty() )
360             {
361                 HostAddresses addresses = encKdcRepPart.getClientAddresses();
362                 for ( HostAddress h : hosts )
363                 {
364                     if ( !addresses.contains( h ) )
365                     {
366                         throw new KerberosException( ErrorType.KRB_ERR_GENERIC,
367                             "requested client address" + h + " is not found in the ticket" );
368                     }
369                 }
370             }
371 
372             // Everything is fine, return the response
373             LOG.debug( "Authentication successful : {}", kdcRep );
374 
375             return new TgTicket( rep.getTicket(), encKdcRepPart, rep.getCName().getNameString() );
376         }
377         catch ( KerberosException ke )
378         {
379             throw ke;
380         }
381         catch ( Exception e )
382         {
383             // We didn't received anything : this is an error
384             LOG.error( "Authentication failed" );
385             throw new KerberosException( ErrorType.KRB_ERR_GENERIC, TIME_OUT_ERROR );
386         }
387         finally
388         {
389             if ( channel != null )
390             {
391                 try
392                 {
393                     channel.close();
394                 }
395                 catch ( IOException e )
396                 {
397                     LOG.warn( "Failed to close the channel", e );
398                 }
399             }
400         }
401     }
402 
403 
404     private ServiceTicket getServiceTicket( ServiceTicketRequest srvTktReq ) throws KerberosException
405     {
406         String serverPrincipal = srvTktReq.getServerPrincipal();
407 
408         // session key
409         EncryptionKey sessionKey = srvTktReq.getTgt().getSessionKey();
410 
411         Authenticatorssages/Authenticator.html#Authenticator">Authenticator authenticator = new Authenticator();
412 
413         try
414         {
415             authenticator.setCName(
416                 new PrincipalName( srvTktReq.getTgt().getClientName(), PrincipalNameType.KRB_NT_PRINCIPAL ) );
417         }
418         catch ( ParseException e )
419         {
420             throw new IllegalArgumentException( "Couldn't parse the given principal", e );
421         }
422 
423         authenticator.setCRealm( srvTktReq.getTgt().getRealm() );
424         authenticator.setCTime( new KerberosTime() );
425         authenticator.setCusec( 0 );
426 
427         if ( srvTktReq.getSubSessionKey() != null )
428         {
429             sessionKey = srvTktReq.getSubSessionKey();
430             authenticator.setSubKey( sessionKey );
431         }
432 
433         EncryptedData authnData = cipherTextHandler.encrypt( sessionKey, getEncoded( authenticator ),
434             KeyUsage.TGS_REQ_PA_TGS_REQ_PADATA_AP_REQ_TGS_SESS_KEY );
435 
436         ApReqared/kerberos/messages/ApReq.html#ApReq">ApReq apReq = new ApReq();
437 
438         apReq.setAuthenticator( authnData );
439         apReq.setTicket( srvTktReq.getTgt().getTicket() );
440 
441         apReq.setApOptions( srvTktReq.getApOptions() );
442 
443         KdcReqBodyros/components/KdcReqBody.html#KdcReqBody">KdcReqBody tgsReqBody = new KdcReqBody();
444         tgsReqBody.setKdcOptions( srvTktReq.getKdcOptions() );
445         tgsReqBody.setRealm( KdcClientUtil.extractRealm( serverPrincipal ) );
446         tgsReqBody.setTill( getDefaultTill() );
447         int currentNonce = nonceGenerator.nextInt();
448         tgsReqBody.setNonce( currentNonce );
449         tgsReqBody.setEType( config.getEncryptionTypes() );
450 
451         PrincipalNamemponents/PrincipalName.html#PrincipalName">PrincipalName principalName = new PrincipalName( KdcClientUtil.extractName( serverPrincipal ),
452             KerberosPrincipal.KRB_NT_SRV_HST );
453         tgsReqBody.setSName( principalName );
454 
455         TgsReqed/kerberos/messages/TgsReq.html#TgsReq">TgsReq tgsReq = new TgsReq();
456         tgsReq.setKdcReqBody( tgsReqBody );
457 
458         PaDatarberos/components/PaData.html#PaData">PaData authnHeader = new PaData();
459         authnHeader.setPaDataType( PaDataType.PA_TGS_REQ );
460         authnHeader.setPaDataValue( getEncoded( apReq ) );
461 
462         tgsReq.addPaData( authnHeader );
463 
464         // Get the result from the future
465         try
466         {
467             connect();
468 
469             // Read the response, waiting for it if not available immediately
470             // Get the response, blocking
471             KerberosMessage kdcRep = sendAndReceiveKrbMsg( tgsReq );
472 
473             if ( kdcRep == null )
474             {
475                 // We didn't received anything : this is an error
476                 LOG.error( "TGT request failed : timeout occured" );
477                 throw new KerberosException( ErrorType.KRB_ERR_GENERIC, TIME_OUT_ERROR );
478             }
479 
480             if ( kdcRep instanceof KrbError )
481             {
482                 // We have an error
483                 LOG.debug( "TGT request failed : {}", kdcRep );
484                 throw new KerberosException( ( KrbError ) kdcRep );
485             }
486 
487             TgsRep="../../../../../org/apache/directory/shared/kerberos/messages/TgsRep.html#TgsRep">TgsRep rep = ( TgsRep ) kdcRep;
488             byte[] decryptedData = cipherTextHandler.decrypt( sessionKey, rep.getEncPart(),
489                 KeyUsage.TGS_REP_ENC_PART_TGS_SESS_KEY );
490             EncTgsRepPart encTgsRepPart = KerberosDecoder.decodeEncTgsRepPart( decryptedData );
491 
492             if ( currentNonce != encTgsRepPart.getEncKdcRepPart().getNonce() )
493             {
494                 throw new KerberosException( ErrorType.KRB_ERR_GENERIC,
495                     "received nonce didn't match with the nonce sent in the request" );
496             }
497 
498             // Everything is fine, return the response
499             LOG.debug( "TGT request successful : {}", rep );
500 
501             return new ServiceTicket( rep.getTicket(), encTgsRepPart.getEncKdcRepPart() );
502         }
503         catch ( KerberosException e )
504         {
505             throw e;
506         }
507         catch ( Exception te )
508         {
509             // We didn't receive anything : this is an error
510             LOG.error( "TGT request failed : timeout occured" );
511             throw new KerberosException( ErrorType.KRB_ERR_GENERIC, TIME_OUT_ERROR );
512         }
513         finally
514         {
515             if ( channel != null )
516             {
517                 try
518                 {
519                     channel.close();
520                 }
521                 catch ( IOException e )
522                 {
523                     LOG.warn( "Failed to close the channel", e );
524                 }
525             }
526         }
527     }
528 
529 
530     public ChangePasswordResult changePassword( String clientPrincipal, String oldPassword, String newPassword )
531         throws ChangePasswordException
532     {
533         KerberosChannel channel = null;
534 
535         try
536         {
537             TgtRequestt/TgtRequest.html#TgtRequest">TgtRequest clientTgtReq = new TgtRequest();
538             clientTgtReq.setClientPrincipal( clientPrincipal );
539             clientTgtReq.setPassword( oldPassword );
540             clientTgtReq.setServerPrincipal( "kadmin/changepw@" + KdcClientUtil.extractRealm( clientPrincipal ) );
541 
542             TgTicket tgt = getTgt( clientTgtReq );
543 
544             ApReqared/kerberos/messages/ApReq.html#ApReq">ApReq apReq = new ApReq();
545             ApOptionserberos/codec/options/ApOptions.html#ApOptions">ApOptions options = new ApOptions();
546             apReq.setApOptions( options );
547             apReq.setTicket( tgt.getTicket() );
548 
549             Authenticatorssages/Authenticator.html#Authenticator">Authenticator authenticator = new Authenticator();
550             authenticator.setCName( new PrincipalName( tgt.getClientName(), PrincipalNameType.KRB_NT_PRINCIPAL ) );
551             authenticator.setCRealm( tgt.getRealm() );
552             KerberosTimerberos/KerberosTime.html#KerberosTime">KerberosTime ctime = new KerberosTime();
553             authenticator.setCTime( ctime );
554             authenticator.setCusec( 0 );
555             authenticator.setSeqNumber( nonceGenerator.nextInt() );
556 
557             EncryptionKey subKey = RandomKeyFactory.getRandomKey( tgt.getEncKdcRepPart().getKey().getKeyType() );
558 
559             authenticator.setSubKey( subKey );
560 
561             EncryptedData authData = cipherTextHandler.encrypt( tgt.getSessionKey(), getEncoded( authenticator ),
562                 KeyUsage.AP_REQ_AUTHNT_SESS_KEY );
563             apReq.setAuthenticator( authData );
564 
565             KrbPrivos/messages/KrbPriv.html#KrbPriv">KrbPriv privateMessage = new KrbPriv();
566 
567             EncKrbPrivPartberos/components/EncKrbPrivPart.html#EncKrbPrivPart">EncKrbPrivPart part = new EncKrbPrivPart();
568             part.setSenderAddress( new HostAddress( Network.LOOPBACK ) );
569             part.setSeqNumber( authenticator.getSeqNumber() );
570             part.setTimestamp( authenticator.getCtime() );
571 
572             short changePwdPVNO = ChangePasswordRequest.PVNO;
573 
574             if ( config.isUseLegacyChngPwdProtocol() )
575             {
576                 part.setUserData( Strings.getBytesUtf8( newPassword ) );
577                 changePwdPVNO = ChangePasswordRequest.OLD_PVNO;
578             }
579             else
580             {
581                 ChangePasswdDatasages/ChangePasswdData.html#ChangePasswdData">ChangePasswdData chngPwdData = new ChangePasswdData();
582                 chngPwdData.setNewPasswd( Strings.getBytesUtf8( newPassword ) );
583                 byte[] data = getEncoded( chngPwdData );
584                 part.setUserData( data );
585             }
586 
587             EncryptedData encKrbPrivPartData = cipherTextHandler.encrypt( subKey, getEncoded( part ),
588                 KeyUsage.KRB_PRIV_ENC_PART_CHOSEN_KEY );
589             privateMessage.setEncPart( encKrbPrivPartData );
590 
591             ChangePasswordRequestchangepwd/messages/ChangePasswordRequest.html#ChangePasswordRequest">ChangePasswordRequest req = new ChangePasswordRequest( changePwdPVNO, apReq, privateMessage );
592 
593             channel = new KerberosChannel();
594             channel.openConnection( config.getHostName(), config.getPasswdPort(), config.getTimeout(),
595                 config.isUseUdp() );
596 
597             AbstractPasswordMessage reply = sendAndReceiveChngPwdMsg( req, channel );
598 
599             if ( reply instanceof ChangePasswordError )
600             {
601                 ChangePasswordError/../org/apache/directory/server/kerberos/changepwd/messages/ChangePasswordError.html#ChangePasswordError">ChangePasswordError err = ( ChangePasswordError ) reply;
602 
603                 return new ChangePasswordResult( err.getKrbError().getEData() );
604             }
605 
606             ChangePasswordReplypache/directory/server/kerberos/changepwd/messages/ChangePasswordReply.html#ChangePasswordReply">ChangePasswordReply chngPwdReply = ( ChangePasswordReply ) reply;
607 
608             KrbPriv replyPriv = chngPwdReply.getPrivateMessage();
609             // the same subKey present in ApReq is used for encrypting the KrbPriv present in reply
610             byte[] data = cipherTextHandler.decrypt( subKey, replyPriv.getEncPart(),
611                 KeyUsage.KRB_PRIV_ENC_PART_CHOSEN_KEY );
612             part = KerberosDecoder.decodeEncKrbPrivPart( data );
613 
614             return new ChangePasswordResult( part.getUserData() );
615         }
616         catch ( ChangePasswordException e )
617         {
618             throw e;
619         }
620         catch ( Exception e )
621         {
622             LOG.warn( "failed to change the password", e );
623             throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_HARDERROR, e );
624         }
625         finally
626         {
627             if ( channel != null )
628             {
629                 try
630                 {
631                     channel.close();
632                 }
633                 catch ( IOException e )
634                 {
635                     LOG.warn( "Failed to close the channel", e );
636                 }
637             }
638         }
639     }
640 
641 
642     private byte[] getEncoded( Asn1Object obj )
643     {
644         try
645         {
646             ByteBuffer buf = ByteBuffer.allocate( obj.computeLength() );
647             obj.encode( buf );
648 
649             return buf.array();
650         }
651         catch ( Exception e )
652         {
653             // shouldn't happen, but if it does then log it and give  up
654             LOG.error( "Failed to encode the ASN.1 object {}", obj );
655             throw new RuntimeException( e );
656         }
657     }
658 
659 
660     private KerberosTime getDefaultTill()
661     {
662         return new KerberosTime( System.currentTimeMillis() + ( KerberosTime.MINUTE * 60 ) );
663     }
664 
665 
666     private KerberosMessageache/directory/shared/kerberos/messages/KerberosMessage.html#KerberosMessage">KerberosMessage sendAndReceiveKrbMsg( KerberosMessage req ) throws Exception
667     {
668         ByteBuffer encodedBuf = KerberosEncoder.encode( req, channel.isUseTcp() );
669         encodedBuf.flip();
670 
671         ByteBuffer repData = channel.sendAndReceive( encodedBuf );
672 
673         KerberosMessageContainertainer.html#KerberosMessageContainer">KerberosMessageContainer kerberosMessageContainer = new KerberosMessageContainer();
674         kerberosMessageContainer.setStream( repData );
675         kerberosMessageContainer.setGathering( true );
676         kerberosMessageContainer.setTCP( channel.isUseTcp() );
677 
678         return ( KerberosMessage ) KerberosDecoder.decode( kerberosMessageContainer );
679     }
680 
681 
682     private AbstractPasswordMessagery/server/kerberos/changepwd/messages/AbstractPasswordMessage.html#AbstractPasswordMessage">AbstractPasswordMessage sendAndReceiveChngPwdMsg( AbstractPasswordMessage req,
683         KerberosChannel chngPwdChannel ) throws Exception
684     {
685         ByteBuffer encodedBuf = ChangePasswordEncoder.encode( req, chngPwdChannel.isUseTcp() );
686         encodedBuf.flip();
687         ByteBuffer repData = chngPwdChannel.sendAndReceive( encodedBuf );
688 
689         return ChangePasswordDecoder.decode( repData, chngPwdChannel.isUseTcp() );
690     }
691 }