001/* 002 * Copyright 2011-2020 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2020 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2011-2020 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk; 037 038 039 040import java.io.File; 041import java.io.FileInputStream; 042import java.util.Arrays; 043 044import com.unboundid.util.Debug; 045import com.unboundid.util.StaticUtils; 046import com.unboundid.util.ThreadSafety; 047import com.unboundid.util.ThreadSafetyLevel; 048import com.unboundid.util.Validator; 049 050import static com.unboundid.ldap.sdk.LDAPMessages.*; 051 052 053 054/** 055 * This class provides an implementation of a password provider that will obtain 056 * the password from a specified file. All bytes up to (but not including) the 057 * first end-of-line character (or to the end of the file if it does not contain 058 * an end-of-line character) will be considered part of the password. 059 */ 060@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 061public final class ReadFromFilePasswordProvider 062 extends PasswordProvider 063{ 064 /** 065 * The serial version UID for this serializable file. 066 */ 067 private static final long serialVersionUID = -3343425971796985100L; 068 069 070 071 // The password file to use. 072 private final File passwordFile; 073 074 075 076 /** 077 * Creates a new instance of this password provider that will read passwords 078 * from the specified file. 079 * 080 * @param passwordFile The path to the file containing the password to use. 081 * It must not be {@code null}. 082 */ 083 public ReadFromFilePasswordProvider(final String passwordFile) 084 { 085 Validator.ensureNotNull(passwordFile); 086 087 this.passwordFile = new File(passwordFile); 088 } 089 090 091 092 /** 093 * Creates a new instance of this password provider that will read passwords 094 * from the specified file. 095 * 096 * @param passwordFile The file containing the password to use. It must not 097 * be {@code null}. 098 */ 099 public ReadFromFilePasswordProvider(final File passwordFile) 100 { 101 Validator.ensureNotNull(passwordFile); 102 103 this.passwordFile = passwordFile; 104 } 105 106 107 108 /** 109 * Retrieves a password in a newly-created byte array. Once the password is 110 * no longer required, the contents of the array will be overwritten so that 111 * the password is no longer contained in memory. 112 * 113 * @return A byte array containing the password that should be used. 114 * 115 * @throws LDAPException If a problem is encountered while attempting to 116 * obtain the password. 117 */ 118 @Override() 119 public byte[] getPasswordBytes() 120 throws LDAPException 121 { 122 byte[] pwBytes = null; 123 124 try 125 { 126 final int fileLength = (int) passwordFile.length(); 127 pwBytes = new byte[fileLength]; 128 129 final FileInputStream inputStream = new FileInputStream(passwordFile); 130 131 try 132 { 133 int pos = 0; 134 while (pos < fileLength) 135 { 136 final int bytesRead = 137 inputStream.read(pwBytes, pos, pwBytes.length - pos); 138 if (bytesRead < 0) 139 { 140 break; 141 } 142 143 pos += bytesRead; 144 } 145 } 146 finally 147 { 148 inputStream.close(); 149 } 150 151 // If there is an end-of-line marker before the end of the file, then 152 // create a password only up to that point and zero out the current array. 153 for (int i=0; i < pwBytes.length; i++) 154 { 155 if ((pwBytes[i] == '\n') || (pwBytes[i] == '\r')) 156 { 157 final byte[] pwWithoutEOL = new byte[i]; 158 System.arraycopy(pwBytes, 0, pwWithoutEOL, 0, i); 159 Arrays.fill(pwBytes, (byte) 0x00); 160 pwBytes = pwWithoutEOL; 161 break; 162 } 163 } 164 } 165 catch (final Exception e) 166 { 167 Debug.debugException(e); 168 169 if (pwBytes != null) 170 { 171 Arrays.fill(pwBytes, (byte) 0x00); 172 } 173 174 throw new LDAPException(ResultCode.LOCAL_ERROR, 175 ERR_FILE_PW_PROVIDER_ERROR_READING_PW.get( 176 passwordFile.getAbsolutePath(), 177 StaticUtils.getExceptionMessage(e)), 178 e); 179 } 180 181 if (pwBytes.length == 0) 182 { 183 throw new LDAPException(ResultCode.PARAM_ERROR, 184 ERR_FILE_PW_PROVIDER_EMPTY_PW.get(passwordFile.getAbsolutePath())); 185 } 186 187 return pwBytes; 188 } 189}