001package com.hfg.security; 002 003import com.hfg.util.StringUtil; 004 005import java.io.BufferedReader; 006import java.io.File; 007import java.io.FileReader; 008import java.util.ArrayList; 009import java.util.List; 010 011//------------------------------------------------------------------------------ 012/** 013 * Simple login store to keep passwords out of the source code. 014 * Unless otherwise specified the default file is called '.credMgr' and is found 015 * in the user's home directory. The file should only be readable by the account owner. 016 * The contents lines are expected to be three whitespace-separated fields: the key, the login, and the password. 017 * 018 * @author J. Alex Taylor, hairyfatguy.com 019 */ 020//------------------------------------------------------------------------------ 021// com.hfg XML/HTML Coding Library 022// 023// This library is free software; you can redistribute it and/or 024// modify it under the terms of the GNU Lesser General Public 025// License as published by the Free Software Foundation; either 026// version 2.1 of the License, or (at your option) any later version. 027// 028// This library 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 GNU 031// Lesser General Public License for more details. 032// 033// You should have received a copy of the GNU Lesser General Public 034// License along with this library; if not, write to the Free Software 035// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 036// 037// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 038// jataylor@hairyfatguy.com 039//------------------------------------------------------------------------------ 040 041public class CredentialsMgr 042{ 043 private File mFile; 044 045 private static String sDefaultFilename = ".credMgr"; 046 047 //########################################################################### 048 // CONSTRUCTORS 049 //########################################################################### 050 051 //--------------------------------------------------------------------------- 052 public CredentialsMgr() 053 { 054 this(new File(System.getProperty("user.home"), sDefaultFilename)); 055 } 056 057 //--------------------------------------------------------------------------- 058 public CredentialsMgr(File inFile) 059 { 060 mFile = inFile; 061 } 062 063 //########################################################################### 064 // PUBLIC METHODS 065 //########################################################################### 066 067 //--------------------------------------------------------------------------- 068 public File getFile() 069 { 070 return mFile; 071 } 072 073 //--------------------------------------------------------------------------- 074 public LoginCredentials get(String inKey) 075 throws SecurityException 076 { 077 LoginCredentials credentials = null; 078 079 if (! mFile.exists()) 080 { 081 throw new SecurityException("The CredentialsMgr file " + StringUtil.singleQuote(mFile.getPath()) + " doesn't exist!"); 082 } 083 else if (! mFile.canRead()) 084 { 085 throw new SecurityException("No permissions for reading the CredentialsMgr file " + StringUtil.singleQuote(mFile.getPath()) + "!"); 086 } 087 088 BufferedReader reader = null; 089 try 090 { 091 try 092 { 093 reader = new BufferedReader(new FileReader(getFile())); 094 String line; 095 while ((line = reader.readLine()) != null) 096 { 097 line = line.trim(); 098 if (line.startsWith("#")) 099 { 100 continue; // Allow comment lines 101 } 102 103 String fields[] = parseLine(line); 104 if (fields.length >= 3 105 && fields[0].equals(inKey)) 106 { 107 credentials = new LoginCredentials(fields[1], fields[2].toCharArray()); 108 break; 109 } 110 } 111 } 112 finally 113 { 114 if (reader != null) 115 { 116 reader.close(); 117 } 118 } 119 } 120 catch (Exception e) 121 { 122 throw new SecurityException("Problem accessing the CredentialsMgr file " + StringUtil.singleQuote(mFile.getPath()) + "!", e); 123 } 124 125 if (null == credentials) 126 { 127 throw new SecurityException("The key " + StringUtil.singleQuote(inKey) 128 + " couldn't be found in the CredentialsMgr file " + StringUtil.singleQuote(mFile.getPath()) + "!"); 129 } 130 131 return credentials; 132 } 133 134 //--------------------------------------------------------------------------- 135 private String[] parseLine(String inLine) 136 { 137 List<String> fields = new ArrayList<>(); 138 139 boolean inQuotedValue = false; 140 int quoteCount = 0; 141 char currentQuoteChar = ' '; 142 StringBuilder currentValue = new StringBuilder(); 143 144 int index = 0; 145 while (index < inLine.length()) 146 { 147 int theChar = inLine.charAt(index); 148 149 if (inQuotedValue) 150 { 151 if (theChar == currentQuoteChar) 152 { 153 quoteCount++; 154 155 if (2 == quoteCount) 156 { 157 // Skip 158 quoteCount = 0; 159 } 160 else if ((index == inLine.length() - 1 || inLine.charAt(index + 1) != currentQuoteChar) 161 && (0 == currentValue.length() || currentValue.charAt(currentValue.length() - 1) != '\\')) 162 { 163 inQuotedValue = false; 164 String unescapedValue = StringUtil.replaceAll(currentValue, "\\" + currentQuoteChar, currentQuoteChar + ""); 165 currentValue.setLength(0); 166 currentValue.append(unescapedValue); 167 } 168 else 169 { 170 currentValue.append((char) theChar); 171 } 172 } 173 else 174 { 175 currentValue.append((char) theChar); 176 quoteCount = 0; 177 } 178 } 179 else if (Character.isWhitespace(theChar)) 180 { 181 if (currentValue.length() > 0) 182 { 183 fields.add(currentValue.toString().trim()); 184 currentValue.setLength(0); 185 } 186 } 187 else if ((theChar == '\'' 188 || theChar == '\"') 189 && 0 == currentValue.length()) 190 { // Start of a quoted value 191 inQuotedValue = true; 192 quoteCount = 0; 193 currentQuoteChar = (char) theChar; 194 } 195 else 196 { 197 currentValue.append((char) theChar); 198 } 199 200 index++; 201 } 202 203 fields.add(currentValue.length() > 0 ? currentValue.toString().trim() : null); 204 205 return fields.toArray(new String[] {}); 206 } 207}