001/* 002 * Copyright 2011-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2011-2024 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-2024 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.NotNull; 046import com.unboundid.util.StaticUtils; 047import com.unboundid.util.ThreadSafety; 048import com.unboundid.util.ThreadSafetyLevel; 049import com.unboundid.util.Validator; 050 051import static com.unboundid.ldap.sdk.LDAPMessages.*; 052 053 054 055/** 056 * This class provides an implementation of a password provider that will obtain 057 * the password from a specified file. All bytes up to (but not including) the 058 * first end-of-line character (or to the end of the file if it does not contain 059 * an end-of-line character) will be considered part of the password. 060 */ 061@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 062public final class ReadFromFilePasswordProvider 063 extends PasswordProvider 064{ 065 /** 066 * The serial version UID for this serializable file. 067 */ 068 private static final long serialVersionUID = -3343425971796985100L; 069 070 071 072 // The password file to use. 073 @NotNull private final File passwordFile; 074 075 076 077 /** 078 * Creates a new instance of this password provider that will read passwords 079 * from the specified file. 080 * 081 * @param passwordFile The path to the file containing the password to use. 082 * It must not be {@code null}. 083 */ 084 public ReadFromFilePasswordProvider(@NotNull final String passwordFile) 085 { 086 Validator.ensureNotNull(passwordFile); 087 088 this.passwordFile = new File(passwordFile); 089 } 090 091 092 093 /** 094 * Creates a new instance of this password provider that will read passwords 095 * from the specified file. 096 * 097 * @param passwordFile The file containing the password to use. It must not 098 * be {@code null}. 099 */ 100 public ReadFromFilePasswordProvider(@NotNull final File passwordFile) 101 { 102 Validator.ensureNotNull(passwordFile); 103 104 this.passwordFile = passwordFile; 105 } 106 107 108 109 /** 110 * Retrieves a password in a newly-created byte array. Once the password is 111 * no longer required, the contents of the array will be overwritten so that 112 * the password is no longer contained in memory. 113 * 114 * @return A byte array containing the password that should be used. 115 * 116 * @throws LDAPException If a problem is encountered while attempting to 117 * obtain the password. 118 */ 119 @Override() 120 @NotNull() 121 public byte[] getPasswordBytes() 122 throws LDAPException 123 { 124 byte[] pwBytes = null; 125 126 try 127 { 128 final int fileLength = (int) passwordFile.length(); 129 pwBytes = new byte[fileLength]; 130 131 final FileInputStream inputStream = new FileInputStream(passwordFile); 132 133 try 134 { 135 int pos = 0; 136 while (pos < fileLength) 137 { 138 final int bytesRead = 139 inputStream.read(pwBytes, pos, pwBytes.length - pos); 140 if (bytesRead < 0) 141 { 142 break; 143 } 144 145 pos += bytesRead; 146 } 147 } 148 finally 149 { 150 inputStream.close(); 151 } 152 153 // If there is an end-of-line marker before the end of the file, then 154 // create a password only up to that point and zero out the current array. 155 for (int i=0; i < pwBytes.length; i++) 156 { 157 if ((pwBytes[i] == '\n') || (pwBytes[i] == '\r')) 158 { 159 final byte[] pwWithoutEOL = new byte[i]; 160 System.arraycopy(pwBytes, 0, pwWithoutEOL, 0, i); 161 Arrays.fill(pwBytes, (byte) 0x00); 162 pwBytes = pwWithoutEOL; 163 break; 164 } 165 } 166 } 167 catch (final Exception e) 168 { 169 Debug.debugException(e); 170 171 if (pwBytes != null) 172 { 173 Arrays.fill(pwBytes, (byte) 0x00); 174 } 175 176 throw new LDAPException(ResultCode.LOCAL_ERROR, 177 ERR_FILE_PW_PROVIDER_ERROR_READING_PW.get( 178 passwordFile.getAbsolutePath(), 179 StaticUtils.getExceptionMessage(e)), 180 e); 181 } 182 183 if (pwBytes.length == 0) 184 { 185 throw new LDAPException(ResultCode.PARAM_ERROR, 186 ERR_FILE_PW_PROVIDER_EMPTY_PW.get(passwordFile.getAbsolutePath())); 187 } 188 189 return pwBytes; 190 } 191}