001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.kerberos.client; 021 022 023import java.io.IOException; 024import java.nio.ByteBuffer; 025import java.security.SecureRandom; 026import java.text.ParseException; 027import java.util.List; 028 029import javax.security.auth.kerberos.KerberosPrincipal; 030 031import org.apache.directory.api.asn1.Asn1Object; 032import org.apache.directory.api.util.Network; 033import org.apache.directory.api.util.Strings; 034import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType; 035import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException; 036import org.apache.directory.server.kerberos.changepwd.io.ChangePasswordDecoder; 037import org.apache.directory.server.kerberos.changepwd.io.ChangePasswordEncoder; 038import org.apache.directory.server.kerberos.changepwd.messages.AbstractPasswordMessage; 039import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordError; 040import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordReply; 041import org.apache.directory.server.kerberos.changepwd.messages.ChangePasswordRequest; 042import org.apache.directory.server.kerberos.shared.crypto.encryption.CipherTextHandler; 043import org.apache.directory.server.kerberos.shared.crypto.encryption.KerberosKeyFactory; 044import org.apache.directory.server.kerberos.shared.crypto.encryption.KeyUsage; 045import org.apache.directory.server.kerberos.shared.crypto.encryption.RandomKeyFactory; 046import org.apache.directory.shared.kerberos.KerberosTime; 047import org.apache.directory.shared.kerberos.codec.KerberosDecoder; 048import org.apache.directory.shared.kerberos.codec.KerberosEncoder; 049import org.apache.directory.shared.kerberos.codec.KerberosMessageContainer; 050import org.apache.directory.shared.kerberos.codec.options.ApOptions; 051import org.apache.directory.shared.kerberos.codec.types.EncryptionType; 052import org.apache.directory.shared.kerberos.codec.types.PaDataType; 053import org.apache.directory.shared.kerberos.codec.types.PrincipalNameType; 054import org.apache.directory.shared.kerberos.components.EncKdcRepPart; 055import org.apache.directory.shared.kerberos.components.EncKrbPrivPart; 056import org.apache.directory.shared.kerberos.components.EncryptedData; 057import org.apache.directory.shared.kerberos.components.EncryptionKey; 058import org.apache.directory.shared.kerberos.components.HostAddress; 059import org.apache.directory.shared.kerberos.components.HostAddresses; 060import org.apache.directory.shared.kerberos.components.KdcReqBody; 061import org.apache.directory.shared.kerberos.components.PaData; 062import org.apache.directory.shared.kerberos.components.PaEncTsEnc; 063import org.apache.directory.shared.kerberos.components.PrincipalName; 064import org.apache.directory.shared.kerberos.exceptions.ErrorType; 065import org.apache.directory.shared.kerberos.exceptions.KerberosException; 066import org.apache.directory.shared.kerberos.messages.ApReq; 067import org.apache.directory.shared.kerberos.messages.AsRep; 068import org.apache.directory.shared.kerberos.messages.AsReq; 069import org.apache.directory.shared.kerberos.messages.Authenticator; 070import org.apache.directory.shared.kerberos.messages.ChangePasswdData; 071import org.apache.directory.shared.kerberos.messages.EncAsRepPart; 072import org.apache.directory.shared.kerberos.messages.EncTgsRepPart; 073import org.apache.directory.shared.kerberos.messages.KerberosMessage; 074import org.apache.directory.shared.kerberos.messages.KrbError; 075import org.apache.directory.shared.kerberos.messages.KrbPriv; 076import org.apache.directory.shared.kerberos.messages.TgsRep; 077import org.apache.directory.shared.kerberos.messages.TgsReq; 078import org.slf4j.Logger; 079import org.slf4j.LoggerFactory; 080 081 082/** 083 * 084 * A client to connect to kerberos servers using TCP or UDP transports. 085 * 086 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 087 */ 088public class KdcConnection 089{ 090 091 private static final Logger LOG = LoggerFactory.getLogger( KdcConnection.class ); 092 093 /** a secure random number generator used for creating nonces */ 094 private SecureRandom nonceGenerator; 095 096 static final String TIME_OUT_ERROR = "TimeOut occured"; 097 098 /** the cipher text handler */ 099 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 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 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 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 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 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 AsReq req = new AsReq(); 265 req.setKdcReqBody( body ); 266 267 if ( clientTgtReq.isPreAuthEnabled() ) 268 { 269 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 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 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 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 ApReq apReq = new ApReq(); 437 438 apReq.setAuthenticator( authnData ); 439 apReq.setTicket( srvTktReq.getTgt().getTicket() ); 440 441 apReq.setApOptions( srvTktReq.getApOptions() ); 442 443 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 PrincipalName principalName = new PrincipalName( KdcClientUtil.extractName( serverPrincipal ), 452 KerberosPrincipal.KRB_NT_SRV_HST ); 453 tgsReqBody.setSName( principalName ); 454 455 TgsReq tgsReq = new TgsReq(); 456 tgsReq.setKdcReqBody( tgsReqBody ); 457 458 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 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 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 ApReq apReq = new ApReq(); 545 ApOptions options = new ApOptions(); 546 apReq.setApOptions( options ); 547 apReq.setTicket( tgt.getTicket() ); 548 549 Authenticator authenticator = new Authenticator(); 550 authenticator.setCName( new PrincipalName( tgt.getClientName(), PrincipalNameType.KRB_NT_PRINCIPAL ) ); 551 authenticator.setCRealm( tgt.getRealm() ); 552 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 KrbPriv privateMessage = new KrbPriv(); 566 567 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 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 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 err = ( ChangePasswordError ) reply; 602 603 return new ChangePasswordResult( err.getKrbError().getEData() ); 604 } 605 606 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 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 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 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}