001: /*
002: * SSHTools - Java SSH2 API
003: *
004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
005: *
006: * Contributions made by:
007: *
008: * Brett Smith
009: * Richard Pernavas
010: * Erwin Bolwidt
011: *
012: * This program is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU General Public License
014: * as published by the Free Software Foundation; either version 2
015: * of the License, or (at your option) any later version.
016: *
017: * This program is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
020: * GNU General Public License for more details.
021: *
022: * You should have received a copy of the GNU General Public License
023: * along with this program; if not, write to the Free Software
024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
025: */
026: package com.sshtools.common.automate;
027:
028: import com.sshtools.j2ssh.SftpClient;
029: import com.sshtools.j2ssh.transport.publickey.SshPublicKey;
030:
031: import org.apache.commons.logging.Log;
032: import org.apache.commons.logging.LogFactory;
033:
034: import java.io.ByteArrayInputStream;
035: import java.io.ByteArrayOutputStream;
036: import java.io.IOException;
037:
038: import java.util.Iterator;
039: import java.util.List;
040: import java.util.Vector;
041:
042: /**
043: *
044: *
045: * @author $author$
046: * @version $Revision: 1.19 $
047: */
048: public class RemoteIdentification {
049: /** */
050: public static final int ADD_AUTHORIZEDKEY = 1;
051:
052: /** */
053: public static final int REMOVE_AUTHORIZEDKEY = 2;
054: private String defaultName;
055: private Vector rules = new Vector();
056: private Class authorizedKeysFormat;
057: private String defaultPath;
058:
059: /** */
060: protected Log log = LogFactory.getLog(RemoteIdentification.class);
061:
062: /**
063: * Creates a new RemoteIdentification object.
064: *
065: * @param defaultName
066: */
067: public RemoteIdentification(String defaultName) {
068: this .defaultName = defaultName;
069: }
070:
071: /**
072: *
073: *
074: * @return
075: */
076: protected List getRules() {
077: return rules;
078: }
079:
080: /**
081: *
082: *
083: * @return
084: */
085: public String getDefaultName() {
086: return defaultName;
087: }
088:
089: /**
090: *
091: *
092: * @param ident
093: *
094: * @return
095: *
096: * @throws RemoteIdentificationException
097: */
098: public String getName(String ident)
099: throws RemoteIdentificationException {
100: boolean pass = false;
101: Iterator it = rules.iterator();
102: Vector passed = new Vector();
103: RemoteIdentificationRule rule;
104: String rulename = null;
105:
106: // Check all the rules
107: while (it.hasNext()) {
108: rule = (RemoteIdentificationRule) it.next();
109:
110: if (rule.testRule(ident)) {
111: passed.add(rule);
112: }
113: }
114:
115: if (passed.size() > 0) {
116: // Select the highest priority rule where 0=highest 10=lowest
117: it = passed.iterator();
118:
119: RemoteIdentificationRule ret = null;
120:
121: while (it.hasNext()) {
122: rule = (RemoteIdentificationRule) it.next();
123:
124: if (ret == null) {
125: ret = rule;
126: } else {
127: if (rule.getPriority() < ret.getPriority()) {
128: ret = rule;
129: }
130: }
131: }
132:
133: if (ret.getName() != null) {
134: return ret.getName();
135: } else {
136: return defaultName;
137: }
138: } else {
139: throw new RemoteIdentificationException(
140: "No rules exist to identify the remote host with ident string "
141: + ident);
142: }
143: }
144:
145: /**
146: *
147: *
148: * @param rule
149: */
150: protected void addRule(RemoteIdentificationRule rule) {
151: rules.add(rule);
152: }
153:
154: /**
155: *
156: *
157: * @param ident
158: *
159: * @return
160: */
161: protected boolean testRules(String ident) {
162: boolean pass = false;
163: Iterator it = rules.iterator();
164: RemoteIdentificationRule rule;
165:
166: while (it.hasNext() && !pass) {
167: rule = (RemoteIdentificationRule) it.next();
168: pass = rule.testRule(ident);
169: }
170:
171: return pass;
172: }
173:
174: /**
175: *
176: *
177: * @param implementationClass
178: */
179: protected void setAuthorizedKeysFormat(Class implementationClass) {
180: authorizedKeysFormat = implementationClass;
181: }
182:
183: /**
184: *
185: *
186: * @param defaultPath
187: */
188: protected void setAuthorizedKeysDefaultPath(String defaultPath) {
189: this .defaultPath = defaultPath;
190: }
191:
192: /**
193: *
194: *
195: * @return
196: */
197: public String getAuthorizedKeysDefaultPath() {
198: return defaultPath;
199: }
200:
201: /**
202: *
203: *
204: * @return
205: *
206: * @throws RemoteIdentificationException
207: */
208: public AuthorizedKeysFormat getAuthorizedKeysFormat()
209: throws RemoteIdentificationException {
210: try {
211: if (authorizedKeysFormat != null) {
212: return (AuthorizedKeysFormat) authorizedKeysFormat
213: .newInstance();
214: } else {
215: throw new RemoteIdentificationException(
216: "There is no authorized keys format set for this remote id");
217: }
218: } catch (Exception ex) {
219: throw new RemoteIdentificationException(
220: "Failed to instansiate "
221: + authorizedKeysFormat.getName());
222: }
223: }
224:
225: /**
226: *
227: *
228: * @param sftp
229: * @param serverId
230: * @param system
231: * @param username
232: * @param pk
233: * @param authorizationFile
234: * @param mode
235: *
236: * @return
237: *
238: * @throws RemoteIdentificationException
239: */
240: public boolean configureUserAccess(SftpClient sftp,
241: String serverId, String system, String username,
242: SshPublicKey pk, String authorizationFile, int mode)
243: throws RemoteIdentificationException {
244: Vector keys = new Vector();
245: keys.add(pk);
246:
247: return configureUserAccess(sftp, serverId, system, username,
248: keys, authorizationFile, mode);
249: }
250:
251: /**
252: *
253: *
254: * @param sftp
255: * @param serverId
256: * @param system
257: * @param username
258: * @param keys
259: * @param authorizationFile
260: * @param mode
261: *
262: * @return
263: *
264: * @throws RemoteIdentificationException
265: */
266: public boolean configureUserAccess(final SftpClient sftp,
267: final String serverId, String system, String username,
268: List keys, String authorizationFile, int mode)
269: throws RemoteIdentificationException {
270: try {
271: if (sftp.isClosed()) {
272: throw new RemoteIdentificationException(
273: "SFTP connection must be open");
274: }
275:
276: if (authorizationFile == null) {
277: throw new RemoteIdentificationException(
278: "authorization file cannot be null");
279: }
280:
281: if ((mode != ADD_AUTHORIZEDKEY)
282: && (mode != REMOVE_AUTHORIZEDKEY)) {
283: throw new RemoteIdentificationException(
284: "Invalid configuration mode specifed in call to configureUserAccess");
285: }
286:
287: AuthorizedKeys authorizedKeys;
288: authorizationFile.replace('\\', '/');
289:
290: final String directory = ((authorizationFile
291: .lastIndexOf("/") > 0) ? authorizationFile
292: .substring(0,
293: authorizationFile.lastIndexOf("/") + 1)
294: : "");
295:
296: try {
297: // Remove the old backup - ignore the error
298: try {
299: sftp.rm(authorizationFile + ".bak");
300: } catch (IOException ex) {
301: }
302:
303: // Change the current authorization file to the backup
304: sftp.rename(authorizationFile, authorizationFile
305: + ".bak");
306: log.info("Opening existing authorized keys file from "
307: + authorizationFile + ".bak");
308:
309: ByteArrayOutputStream out = new ByteArrayOutputStream();
310: sftp.get(authorizationFile + ".bak", out);
311:
312: byte[] backup = out.toByteArray();
313: out.close();
314:
315: // Obtain the current authoized keys settings
316: log.info("Parsing authorized keys file");
317: authorizedKeys = AuthorizedKeys.parse(backup, serverId,
318: system, new AuthorizedKeysFileLoader() {
319: public byte[] loadFile(String filename)
320: throws IOException {
321: ByteArrayOutputStream out = new ByteArrayOutputStream();
322: sftp.get(directory + filename, out);
323: out.close();
324:
325: return out.toByteArray();
326: }
327: });
328: } catch (IOException ioe) {
329: // Could not open so create a new file
330: authorizedKeys = new AuthorizedKeys();
331: } catch (RemoteIdentificationException rie) {
332: throw new RemoteIdentificationException(
333: "Open3SP cannot identify the remote host.\n"
334: + "Please email support@open3sp.org with specifying 'remote identification' in the subject and supplying the server type and the follwing data '"
335: + serverId + "'");
336: }
337:
338: log.info("Updating authorized keys file");
339:
340: // Check the existing keys and add any that are not present
341: SshPublicKey pk;
342:
343: for (Iterator x = keys.iterator(); x.hasNext();) {
344: pk = (SshPublicKey) x.next();
345:
346: if (!authorizedKeys.containsKey(pk)
347: && (mode == ADD_AUTHORIZEDKEY)) {
348: authorizedKeys.addKey(username, pk);
349: } else if (authorizedKeys.containsKey(pk)
350: && (mode == REMOVE_AUTHORIZEDKEY)) {
351: authorizedKeys.removeKey(pk);
352: }
353: }
354:
355: // Verfiy that the directory exists?
356: log.info("Verifying directory " + directory);
357:
358: int umask = sftp.umask(0022);
359: sftp.mkdirs(directory);
360:
361: // Output the new file
362: log.info("Writing new authorized keys file to "
363: + authorizationFile);
364:
365: ByteArrayOutputStream out = new ByteArrayOutputStream();
366:
367: // Output the authorization file to a ByteArrayOutputStream
368: out.write(AuthorizedKeys.create(authorizedKeys, serverId,
369: system, new AuthorizedKeysFileSaver() {
370: public void saveFile(String filename,
371: byte[] filedata) throws IOException {
372: //SftpFile file = null;
373: ByteArrayInputStream in = null;
374:
375: try {
376: in = new ByteArrayInputStream(filedata);
377: sftp.put(in, directory + filename);
378: } catch (IOException ex) {
379: log.info(
380: "Error writing public key file to server"
381: + filename, ex);
382: } finally {
383: if (in != null) {
384: in.close();
385: }
386: }
387: }
388: }));
389: out.close();
390:
391: // Copy the new authorisation file to the server
392: ByteArrayInputStream in = new ByteArrayInputStream(out
393: .toByteArray());
394: sftp.umask(0133);
395: sftp.put(in, authorizationFile);
396: sftp.umask(umask);
397:
398: return true;
399: } catch (IOException ioe) {
400: throw new RemoteIdentificationException(ioe.getMessage());
401: } catch (RemoteIdentificationException rie) {
402: throw new RemoteIdentificationException(
403: "SSHTools cannot identify the remote host.\n"
404: + "Please email support@sshtools.com specifying 'remote identification' in the subject, supplying the server type and the following data: '"
405: + serverId + "'");
406: }
407: }
408: }
|