001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.extensions; 028 import org.opends.messages.Message; 029 030 031 032 import java.io.BufferedReader; 033 import java.io.File; 034 import java.io.FileInputStream; 035 import java.io.FileReader; 036 import java.io.IOException; 037 import java.security.KeyStore; 038 import java.security.KeyStoreException; 039 import java.util.ArrayList; 040 import java.util.List; 041 import javax.net.ssl.KeyManager; 042 import javax.net.ssl.KeyManagerFactory; 043 044 import org.opends.server.admin.server.ConfigurationChangeListener; 045 import org.opends.server.admin.std.server.FileBasedKeyManagerProviderCfg; 046 import org.opends.server.api.KeyManagerProvider; 047 import org.opends.server.config.ConfigException; 048 import org.opends.server.core.DirectoryServer; 049 import org.opends.server.types.ConfigChangeResult; 050 import org.opends.server.types.DirectoryException; 051 import org.opends.server.types.DN; 052 import org.opends.server.types.InitializationException; 053 import org.opends.server.types.ResultCode; 054 055 import static org.opends.server.loggers.debug.DebugLogger.*; 056 import org.opends.server.loggers.debug.DebugTracer; 057 import org.opends.server.types.DebugLogLevel; 058 import static org.opends.messages.ExtensionMessages.*; 059 060 import static org.opends.server.util.StaticUtils.*; 061 062 063 064 /** 065 * This class defines a key manager provider that will access keys stored in a 066 * file located on the Directory Server filesystem. 067 */ 068 public class FileBasedKeyManagerProvider 069 extends KeyManagerProvider<FileBasedKeyManagerProviderCfg> 070 implements ConfigurationChangeListener<FileBasedKeyManagerProviderCfg> 071 { 072 /** 073 * The tracer object for the debug logger. 074 */ 075 private static final DebugTracer TRACER = getTracer(); 076 077 078 079 // The DN of the configuration entry for this key manager provider. 080 private DN configEntryDN; 081 082 // The PIN needed to access the keystore. 083 private char[] keyStorePIN; 084 085 // The configuration for this key manager provider. 086 private FileBasedKeyManagerProviderCfg currentConfig; 087 088 // The path to the key store backing file. 089 private String keyStoreFile; 090 091 // The key store type to use. 092 private String keyStoreType; 093 094 095 096 /** 097 * Creates a new instance of this file-based key manager provider. The 098 * <CODE>initializeKeyManagerProvider</CODE> method must be called on the 099 * resulting object before it may be used. 100 */ 101 public FileBasedKeyManagerProvider() 102 { 103 // No implementation is required. 104 } 105 106 107 108 /** 109 * {@inheritDoc} 110 */ 111 @Override 112 public void initializeKeyManagerProvider( 113 FileBasedKeyManagerProviderCfg configuration) 114 throws ConfigException, InitializationException { 115 // Store the DN of the configuration entry and register as a change 116 // listener. 117 currentConfig = configuration; 118 configEntryDN = configuration.dn(); 119 configuration.addFileBasedChangeListener(this); 120 121 122 // Get the path to the key store file. 123 keyStoreFile = configuration.getKeyStoreFile(); 124 try { 125 File f = getFileForPath(keyStoreFile); 126 if (!(f.exists() && f.isFile())) { 127 Message message = ERR_FILE_KEYMANAGER_NO_SUCH_FILE.get( 128 String.valueOf(keyStoreFile), String.valueOf(configEntryDN)); 129 throw new InitializationException(message); 130 } 131 } catch (SecurityException e) { 132 if (debugEnabled()) 133 { 134 TRACER.debugCaught(DebugLogLevel.ERROR, e); 135 } 136 137 Message message = ERR_FILE_KEYMANAGER_CANNOT_DETERMINE_FILE.get( 138 String.valueOf(configEntryDN), getExceptionMessage(e)); 139 throw new InitializationException(message, e); 140 } 141 142 // Get the keystore type. If none is specified, then use the 143 // default type. 144 if (configuration.getKeyStoreType() != null) { 145 try { 146 KeyStore.getInstance(configuration.getKeyStoreType()); 147 keyStoreType = configuration.getKeyStoreType(); 148 } catch (KeyStoreException kse) { 149 if (debugEnabled()) 150 { 151 TRACER.debugCaught(DebugLogLevel.ERROR, kse); 152 } 153 154 Message message = ERR_FILE_KEYMANAGER_INVALID_TYPE. 155 get(String.valueOf(configuration.getKeyStoreType()), 156 String.valueOf(configEntryDN), getExceptionMessage(kse)); 157 throw new InitializationException(message); 158 } 159 } else { 160 keyStoreType = KeyStore.getDefaultType(); 161 } 162 163 // Get the PIN needed to access the contents of the keystore file. 164 // 165 // We will offer several places to look for the PIN, and we will 166 // do so in the following order: 167 // 168 // - In a specified Java property 169 // - In a specified environment variable 170 // - In a specified file on the server filesystem. 171 // - As the value of a configuration attribute. 172 // 173 // In any case, the PIN must be in the clear. 174 keyStorePIN = null; 175 176 if (configuration.getKeyStorePinProperty() != null) { 177 String propertyName = configuration.getKeyStorePinProperty(); 178 String pinStr = System.getProperty(propertyName); 179 180 if (pinStr == null) { 181 Message message = ERR_FILE_KEYMANAGER_PIN_PROPERTY_NOT_SET.get( 182 String.valueOf(propertyName), String.valueOf(configEntryDN)); 183 throw new InitializationException(message); 184 } 185 186 keyStorePIN = pinStr.toCharArray(); 187 } else if (configuration.getKeyStorePinEnvironmentVariable() != null) { 188 String enVarName = configuration 189 .getKeyStorePinEnvironmentVariable(); 190 String pinStr = System.getenv(enVarName); 191 192 if (pinStr == null) { 193 Message message = ERR_FILE_KEYMANAGER_PIN_ENVAR_NOT_SET.get( 194 String.valueOf(enVarName), String.valueOf(configEntryDN)); 195 throw new InitializationException(message); 196 } 197 198 keyStorePIN = pinStr.toCharArray(); 199 } else if (configuration.getKeyStorePinFile() != null) { 200 String fileName = configuration.getKeyStorePinFile(); 201 File pinFile = getFileForPath(fileName); 202 203 if (!pinFile.exists()) { 204 Message message = ERR_FILE_KEYMANAGER_PIN_NO_SUCH_FILE.get( 205 String.valueOf(fileName), String.valueOf(configEntryDN)); 206 throw new InitializationException(message); 207 } 208 209 String pinStr; 210 try { 211 BufferedReader br = new BufferedReader( 212 new FileReader(pinFile)); 213 pinStr = br.readLine(); 214 br.close(); 215 } catch (IOException ioe) { 216 Message message = ERR_FILE_KEYMANAGER_PIN_FILE_CANNOT_READ. 217 get(String.valueOf(fileName), String.valueOf(configEntryDN), 218 getExceptionMessage(ioe)); 219 throw new InitializationException(message, ioe); 220 } 221 222 if (pinStr == null) { 223 Message message = ERR_FILE_KEYMANAGER_PIN_FILE_EMPTY.get( 224 String.valueOf(fileName), String.valueOf(configEntryDN)); 225 throw new InitializationException(message); 226 } 227 228 keyStorePIN = pinStr.toCharArray(); 229 } else if (configuration.getKeyStorePin() != null) { 230 keyStorePIN = configuration.getKeyStorePin().toCharArray(); 231 } else { 232 // Pin wasn't defined anywhere. 233 Message message = 234 ERR_FILE_KEYMANAGER_NO_PIN.get(String.valueOf(configEntryDN)); 235 throw new ConfigException(message); 236 } 237 } 238 239 240 241 /** 242 * Performs any finalization that may be necessary for this key 243 * manager provider. 244 */ 245 public void finalizeKeyManagerProvider() 246 { 247 currentConfig.removeFileBasedChangeListener(this); 248 } 249 250 251 252 /** 253 * Retrieves a set of <CODE>KeyManager</CODE> objects that may be used for 254 * interactions requiring access to a key manager. 255 * 256 * @return A set of <CODE>KeyManager</CODE> objects that may be used for 257 * interactions requiring access to a key manager. 258 * 259 * @throws DirectoryException If a problem occurs while attempting to obtain 260 * the set of key managers. 261 */ 262 public KeyManager[] getKeyManagers() 263 throws DirectoryException 264 { 265 KeyStore keyStore; 266 try 267 { 268 keyStore = KeyStore.getInstance(keyStoreType); 269 270 FileInputStream inputStream = 271 new FileInputStream(getFileForPath(keyStoreFile)); 272 keyStore.load(inputStream, keyStorePIN); 273 inputStream.close(); 274 } 275 catch (Exception e) 276 { 277 if (debugEnabled()) 278 { 279 TRACER.debugCaught(DebugLogLevel.ERROR, e); 280 } 281 282 Message message = ERR_FILE_KEYMANAGER_CANNOT_LOAD.get( 283 keyStoreFile, getExceptionMessage(e)); 284 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 285 message, e); 286 } 287 288 289 try 290 { 291 String keyManagerAlgorithm = KeyManagerFactory.getDefaultAlgorithm(); 292 KeyManagerFactory keyManagerFactory = 293 KeyManagerFactory.getInstance(keyManagerAlgorithm); 294 keyManagerFactory.init(keyStore, keyStorePIN); 295 return keyManagerFactory.getKeyManagers(); 296 } 297 catch (Exception e) 298 { 299 if (debugEnabled()) 300 { 301 TRACER.debugCaught(DebugLogLevel.ERROR, e); 302 } 303 304 Message message = ERR_FILE_KEYMANAGER_CANNOT_CREATE_FACTORY.get( 305 keyStoreFile, getExceptionMessage(e)); 306 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), 307 message, e); 308 } 309 } 310 311 312 313 /** 314 * {@inheritDoc} 315 */ 316 @Override() 317 public boolean isConfigurationAcceptable( 318 FileBasedKeyManagerProviderCfg configuration, 319 List<Message> unacceptableReasons) 320 { 321 return isConfigurationChangeAcceptable(configuration, unacceptableReasons); 322 } 323 324 325 326 /** 327 * {@inheritDoc} 328 */ 329 public boolean isConfigurationChangeAcceptable( 330 FileBasedKeyManagerProviderCfg configuration, 331 List<Message> unacceptableReasons) 332 { 333 boolean configAcceptable = true; 334 DN cfgEntryDN = configuration.dn(); 335 336 337 // Get the path to the key store file. 338 String newKeyStoreFile = configuration.getKeyStoreFile(); 339 try 340 { 341 File f = getFileForPath(newKeyStoreFile); 342 if (!(f.exists() && f.isFile())) 343 { 344 unacceptableReasons.add(ERR_FILE_KEYMANAGER_NO_SUCH_FILE.get( 345 String.valueOf(newKeyStoreFile), 346 String.valueOf(cfgEntryDN))); 347 configAcceptable = false; 348 } 349 } 350 catch (Exception e) 351 { 352 if (debugEnabled()) 353 { 354 TRACER.debugCaught(DebugLogLevel.ERROR, e); 355 } 356 357 unacceptableReasons.add(ERR_FILE_KEYMANAGER_CANNOT_DETERMINE_FILE.get( 358 String.valueOf(cfgEntryDN), 359 getExceptionMessage(e))); 360 configAcceptable = false; 361 } 362 363 // Get the keystore type. If none is specified, then use the default type. 364 if (configuration.getKeyStoreType() != null) 365 { 366 try 367 { 368 KeyStore.getInstance(configuration.getKeyStoreType()); 369 } 370 catch (KeyStoreException kse) 371 { 372 if (debugEnabled()) 373 { 374 TRACER.debugCaught(DebugLogLevel.ERROR, kse); 375 } 376 377 unacceptableReasons.add(ERR_FILE_KEYMANAGER_INVALID_TYPE.get( 378 String.valueOf(configuration.getKeyStoreType()), 379 String.valueOf(cfgEntryDN), getExceptionMessage(kse))); 380 configAcceptable = false; 381 } 382 } 383 384 // Get the PIN needed to access the contents of the keystore file. 385 // 386 // We will offer several places to look for the PIN, and we will 387 // do so in the following order: 388 // 389 // - In a specified Java property 390 // - In a specified environment variable 391 // - In a specified file on the server filesystem. 392 // - As the value of a configuration attribute. 393 // 394 // In any case, the PIN must be in the clear. 395 if (configuration.getKeyStorePinProperty() != null) 396 { 397 String propertyName = configuration.getKeyStorePinProperty(); 398 String pinStr = System.getProperty(propertyName); 399 400 if (pinStr == null) 401 { 402 unacceptableReasons.add(ERR_FILE_KEYMANAGER_PIN_PROPERTY_NOT_SET.get( 403 String.valueOf(propertyName), 404 String.valueOf(cfgEntryDN))); 405 configAcceptable = false; 406 } 407 } 408 else if (configuration.getKeyStorePinEnvironmentVariable() != null) 409 { 410 String enVarName = configuration.getKeyStorePinEnvironmentVariable(); 411 String pinStr = System.getenv(enVarName); 412 413 if (pinStr == null) 414 { 415 unacceptableReasons.add(ERR_FILE_KEYMANAGER_PIN_ENVAR_NOT_SET.get( 416 String.valueOf(enVarName), 417 String.valueOf(cfgEntryDN))); 418 configAcceptable = false; 419 } 420 } 421 else if (configuration.getKeyStorePinFile() != null) 422 { 423 String fileName = configuration.getKeyStorePinFile(); 424 File pinFile = getFileForPath(fileName); 425 426 if (!pinFile.exists()) 427 { 428 unacceptableReasons.add(ERR_FILE_KEYMANAGER_PIN_NO_SUCH_FILE.get( 429 String.valueOf(fileName), 430 String.valueOf(cfgEntryDN))); 431 configAcceptable = false; 432 } 433 else 434 { 435 String pinStr = null; 436 BufferedReader br = null; 437 try { 438 br = new BufferedReader(new FileReader(pinFile)); 439 pinStr = br.readLine(); 440 } 441 catch (IOException ioe) 442 { 443 unacceptableReasons.add(ERR_FILE_KEYMANAGER_PIN_FILE_CANNOT_READ.get( 444 String.valueOf(fileName), 445 String.valueOf(cfgEntryDN), 446 getExceptionMessage(ioe))); 447 configAcceptable = false; 448 } 449 finally 450 { 451 try 452 { 453 br.close(); 454 } catch (Exception e) {} 455 } 456 457 if (pinStr == null) 458 { 459 unacceptableReasons.add(ERR_FILE_KEYMANAGER_PIN_FILE_EMPTY.get( 460 String.valueOf(fileName), 461 String.valueOf(cfgEntryDN))); 462 configAcceptable = false; 463 } 464 } 465 } 466 else if (configuration.getKeyStorePin() != null) 467 { 468 configuration.getKeyStorePin().toCharArray(); 469 } 470 else 471 { 472 // Pin wasn't defined anywhere. 473 unacceptableReasons.add(ERR_FILE_KEYMANAGER_NO_PIN.get( 474 String.valueOf(cfgEntryDN))); 475 configAcceptable = false; 476 } 477 478 return configAcceptable; 479 } 480 481 482 483 /** 484 * {@inheritDoc} 485 */ 486 public ConfigChangeResult applyConfigurationChange( 487 FileBasedKeyManagerProviderCfg configuration) 488 { 489 ResultCode resultCode = ResultCode.SUCCESS; 490 boolean adminActionRequired = false; 491 ArrayList<Message> messages = new ArrayList<Message>(); 492 493 494 // Get the path to the key store file. 495 String newKeyStoreFile = configuration.getKeyStoreFile(); 496 try 497 { 498 File f = getFileForPath(newKeyStoreFile); 499 if (!(f.exists() && f.isFile())) 500 { 501 resultCode = DirectoryServer.getServerErrorResultCode(); 502 503 messages.add(ERR_FILE_KEYMANAGER_NO_SUCH_FILE.get( 504 String.valueOf(newKeyStoreFile), 505 String.valueOf(configEntryDN))); 506 } 507 } 508 catch (Exception e) 509 { 510 if (debugEnabled()) 511 { 512 TRACER.debugCaught(DebugLogLevel.ERROR, e); 513 } 514 515 resultCode = DirectoryServer.getServerErrorResultCode(); 516 517 messages.add(ERR_FILE_KEYMANAGER_CANNOT_DETERMINE_FILE.get( 518 String.valueOf(configEntryDN), 519 getExceptionMessage(e))); 520 } 521 522 // Get the keystore type. If none is specified, then use the default type. 523 String newKeyStoreType = KeyStore.getDefaultType(); 524 if (configuration.getKeyStoreType() != null) 525 { 526 try 527 { 528 KeyStore.getInstance(configuration.getKeyStoreType()); 529 newKeyStoreType = configuration.getKeyStoreType(); 530 } 531 catch (KeyStoreException kse) 532 { 533 if (debugEnabled()) 534 { 535 TRACER.debugCaught(DebugLogLevel.ERROR, kse); 536 } 537 538 resultCode = DirectoryServer.getServerErrorResultCode(); 539 540 messages.add(ERR_FILE_KEYMANAGER_INVALID_TYPE.get( 541 String.valueOf(configuration.getKeyStoreType()), 542 String.valueOf(configEntryDN), 543 getExceptionMessage(kse))); 544 } 545 } 546 547 // Get the PIN needed to access the contents of the keystore file. 548 // 549 // We will offer several places to look for the PIN, and we will 550 // do so in the following order: 551 // 552 // - In a specified Java property 553 // - In a specified environment variable 554 // - In a specified file on the server filesystem. 555 // - As the value of a configuration attribute. 556 // 557 // In any case, the PIN must be in the clear. 558 char[] newPIN = null; 559 560 if (configuration.getKeyStorePinProperty() != null) 561 { 562 String propertyName = configuration.getKeyStorePinProperty(); 563 String pinStr = System.getProperty(propertyName); 564 565 if (pinStr == null) 566 { 567 resultCode = DirectoryServer.getServerErrorResultCode(); 568 569 messages.add(ERR_FILE_KEYMANAGER_PIN_PROPERTY_NOT_SET.get( 570 String.valueOf(propertyName), 571 String.valueOf(configEntryDN))); 572 } 573 else 574 { 575 newPIN = pinStr.toCharArray(); 576 } 577 } 578 else if (configuration.getKeyStorePinEnvironmentVariable() != null) 579 { 580 String enVarName = configuration.getKeyStorePinEnvironmentVariable(); 581 String pinStr = System.getenv(enVarName); 582 583 if (pinStr == null) 584 { 585 resultCode = DirectoryServer.getServerErrorResultCode(); 586 587 messages.add(ERR_FILE_KEYMANAGER_PIN_ENVAR_NOT_SET.get( 588 String.valueOf(enVarName), 589 String.valueOf(configEntryDN))); 590 } 591 else 592 { 593 newPIN = pinStr.toCharArray(); 594 } 595 } 596 else if (configuration.getKeyStorePinFile() != null) 597 { 598 String fileName = configuration.getKeyStorePinFile(); 599 File pinFile = getFileForPath(fileName); 600 601 if (!pinFile.exists()) 602 { 603 resultCode = DirectoryServer.getServerErrorResultCode(); 604 605 messages.add(ERR_FILE_KEYMANAGER_PIN_NO_SUCH_FILE.get( 606 String.valueOf(fileName), 607 String.valueOf(configEntryDN))); 608 } 609 else 610 { 611 String pinStr = null; 612 BufferedReader br = null; 613 try { 614 br = new BufferedReader(new FileReader(pinFile)); 615 pinStr = br.readLine(); 616 } 617 catch (IOException ioe) 618 { 619 resultCode = DirectoryServer.getServerErrorResultCode(); 620 621 messages.add(ERR_FILE_KEYMANAGER_PIN_FILE_CANNOT_READ.get( 622 String.valueOf(fileName), 623 String.valueOf(configEntryDN), 624 getExceptionMessage(ioe))); 625 } 626 finally 627 { 628 try 629 { 630 br.close(); 631 } catch (Exception e) {} 632 } 633 634 if (pinStr == null) 635 { 636 resultCode = DirectoryServer.getServerErrorResultCode(); 637 638 messages.add(ERR_FILE_KEYMANAGER_PIN_FILE_EMPTY.get( 639 String.valueOf(fileName), 640 String.valueOf(configEntryDN))); 641 } 642 else 643 { 644 newPIN = pinStr.toCharArray(); 645 } 646 } 647 } 648 else if (configuration.getKeyStorePin() != null) 649 { 650 newPIN = configuration.getKeyStorePin().toCharArray(); 651 } 652 else 653 { 654 // Pin wasn't defined anywhere. 655 resultCode = DirectoryServer.getServerErrorResultCode(); 656 657 messages.add(ERR_FILE_KEYMANAGER_NO_PIN.get( 658 String.valueOf(configEntryDN))); 659 } 660 661 662 if (resultCode == ResultCode.SUCCESS) 663 { 664 currentConfig = configuration; 665 keyStorePIN = newPIN; 666 keyStoreFile = newKeyStoreFile; 667 keyStoreType = newKeyStoreType; 668 } 669 670 671 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 672 } 673 } 674