001: /******************************************************************************
002: * $Source: /cvsroot/sshwebproxy/src/java/com/ericdaugherty/sshwebproxy/SshConnectionServlet.java,v $
003: * $Revision: 1.2 $
004: * $Author: edaugherty $
005: * $Date: 2003/11/23 00:18:10 $
006: ******************************************************************************
007: * Copyright (c) 2003, Eric Daugherty (http://www.ericdaugherty.com)
008: * All rights reserved.
009: *
010: * Redistribution and use in source and binary forms, with or without
011: * modification, are permitted provided that the following conditions are met:
012: *
013: * * Redistributions of source code must retain the above copyright notice,
014: * this list of conditions and the following disclaimer.
015: * * Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in the
017: * documentation and/or other materials provided with the distribution.
018: * * Neither the name of the Eric Daugherty nor the names of its
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
023: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
024: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
025: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
026: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
027: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
028: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
029: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
030: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
031: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
032: * THE POSSIBILITY OF SUCH DAMAGE.
033: * *****************************************************************************
034: * For current versions and more information, please visit:
035: * http://www.ericdaugherty.com/dev/sshwebproxy
036: *
037: * or contact the author at:
038: * web@ericdaugherty.com
039: *****************************************************************************/package com.ericdaugherty.sshwebproxy;
040:
041: import org.apache.commons.logging.LogFactory;
042: import org.apache.commons.logging.Log;
043: import org.apache.commons.fileupload.*;
044:
045: import javax.servlet.http.HttpServletRequest;
046: import javax.servlet.http.HttpServletResponse;
047: import javax.servlet.http.HttpServlet;
048: import javax.servlet.ServletException;
049: import java.io.*;
050: import java.util.List;
051: import java.util.Iterator;
052:
053: /**
054: * Handles the managment of SsshConnections, and the creation
055: * and closing of SshChannels.
056: *
057: * @author Eric Daugherty
058: */
059: public class SshConnectionServlet extends HttpServlet implements
060: SshConstants {
061:
062: //***************************************************************
063: // Variables
064: //***************************************************************
065:
066: /** Logger */
067: private static final Log log = LogFactory
068: .getLog(SshConnectionServlet.class);
069:
070: //***************************************************************
071: // HTTPServlet Methods
072: //***************************************************************
073:
074: protected void doGet(HttpServletRequest request,
075: HttpServletResponse response) throws ServletException,
076: IOException {
077: log.warn("doGet called, but is not implemented.");
078: response.sendRedirect(PAGE_HOME);
079: }
080:
081: /**
082: * Handles requests from the SHH client JSP page. All requests from
083: * that page should be via POST.
084: *
085: * @param request
086: * @param response
087: * @throws ServletException
088: * @throws IOException
089: */
090: protected void doPost(HttpServletRequest request,
091: HttpServletResponse response) throws ServletException,
092: IOException {
093: // Validate login.
094: SshSession sshSession = new SshSession(request);
095: if (!sshSession.isValid()) {
096: response.sendRedirect(SshConstants.PAGE_LOGIN);
097: return;
098: }
099:
100: String action = request.getParameter(PARAMETER_ACTION);
101: List multiPartItems = null;
102:
103: if (FileUpload.isMultipartContent(request)) {
104: try {
105: DiskFileUpload upload = new DiskFileUpload();
106: // Parse the parts into Parameters and the file.
107: multiPartItems = upload.parseRequest(request);
108: } catch (FileUploadException fileUploadException) {
109: log.error("Error parsing MultiPart Upload!",
110: fileUploadException);
111: }
112:
113: action = getParameter(multiPartItems, PARAMETER_ACTION);
114: }
115:
116: // Verify we received an action to perform.
117: if (action == null || action.trim().length() == 0) {
118: log
119: .warn("POST Request received without an action parameter.");
120: response.sendRedirect(PAGE_HOME);
121: }
122:
123: action = action.trim();
124:
125: if (ACTION_OPEN_CONNECTION.equals(action)) {
126: openConnection(request, response, multiPartItems);
127: } else if (ACTION_CLOSE_CONNECTION.equals(action)) {
128: closeConnection(request, response);
129: } else if (ACTION_OPEN_SHELL_CHANNEL.equals(action)) {
130: openShellChannel(request, response);
131: } else if (ACTION_OPEN_FILE_CHANNEL.equals(action)) {
132: openFileChannel(request, response);
133: } else if (ACTION_CLOSE_CHANNEL.equals(action)) {
134: closeChannel(request, response);
135: } else {
136: log
137: .warn("POST Request received with an invalid action parameter: "
138: + action);
139: response.sendRedirect(PAGE_HOME);
140: }
141: }
142:
143: //***************************************************************
144: // Private Action Handlers
145: //***************************************************************
146:
147: /**
148: * Attempts to create a new SSH Connection.
149: *
150: * @param request original HttpServletRequest
151: * @param response original HttpServletResponse
152: */
153: private void openConnection(HttpServletRequest request,
154: HttpServletResponse response, List multiPartItems)
155: throws IOException {
156: log.debug("Connection request received.");
157:
158: SshSession session = new SshSession(request);
159:
160: String error = null;
161: String host = getParameter(multiPartItems, PARAMETER_HOST);
162: String port = getParameter(multiPartItems, PARAMETER_PORT);
163:
164: // If we are in restricted mode, override whatever may have come
165: // from the client.
166: if (session.isRestrictedMode()) {
167: host = session.getRestrictedModeHost();
168: port = "22";
169: }
170:
171: String username = getParameter(multiPartItems,
172: PARAMETER_USERNAME);
173: String authenticationType = getParameter(multiPartItems,
174: PARAMETER_AUTHENTICATION_TYPE);
175:
176: // Determine which authentication method to use.
177: boolean isKeyAuthentication = false;
178: if (authenticationType != null
179: && authenticationType.equals(AUTHENTICATION_TYPE_KEY)) {
180: isKeyAuthentication = true;
181: }
182:
183: // Parse the authentication parameters
184: String password = null;
185: FileItem keyFileItem = null;
186: String keyPassPhrase = null;
187: if (!isKeyAuthentication) {
188: password = getParameter(multiPartItems, PARAMETER_PASSWORD);
189: } else {
190: keyFileItem = getFile(multiPartItems);
191: keyPassPhrase = getParameter(multiPartItems,
192: PARAMETER_KEY_PASSWORD);
193: }
194:
195: String channelType = getParameter(multiPartItems,
196: PARAMETER_CHANNEL_TYPE);
197:
198: // Validate all input parameters exist.
199: if (host == null || host.trim().length() == 0 || port == null
200: || port.trim().length() == 0) {
201: error = "Please specify a valid host and port.";
202: } else if (!isKeyAuthentication
203: && (username == null || username.trim().length() == 0
204: || password == null || password.trim().length() == 0)) {
205: error = "Please specify a valid username and password.";
206: } else if (isKeyAuthentication && (keyFileItem == null)) {
207: error = "Please specify a key file.";
208: }
209:
210: int portInt = 22;
211: try {
212: portInt = Integer.parseInt(port);
213: } catch (NumberFormatException numberFormatException) {
214: error = "The port number must be an integer.";
215: }
216:
217: if (error == null) {
218: try {
219: // Look for an existing open connection.
220: String connectionInfo = SshConnection
221: .getConnectionInfo(host, port, username);
222: SshConnection sshConnection = session
223: .getSshConnection(connectionInfo);
224:
225: // If the connection does not exist yet, open a new one.
226: if (sshConnection == null) {
227: log
228: .debug("Connection does not exist, opening new connection.");
229: if (isKeyAuthentication) {
230: sshConnection = new SshConnection(host,
231: portInt, username, keyFileItem.get(),
232: keyPassPhrase);
233: } else {
234: sshConnection = new SshConnection(host,
235: portInt, username, password);
236: }
237:
238: // If there is a collision adding it to the session, then one
239: // must have been created while we were creating ours. Close ours
240: // and use the other one.
241: if (!session.addSshConnection(sshConnection)) {
242: log
243: .warn("addSshConnection race condition occured. Closing duplicate session!");
244: sshConnection.close();
245: sshConnection = session
246: .getSshConnection(connectionInfo);
247: if (sshConnection == null) {
248: log
249: .error("Failed to get connection from session after closing new connection! Giving up!");
250: session
251: .setErrorMessage("Error Opening Connection.");
252: response.sendRedirect(PAGE_HOME);
253: return;
254: }
255: }
256: }
257:
258: // Open the requested SshChannel
259: if (channelType != null
260: && CHANNEL_TYPE_SHELL.equals(channelType)) {
261: openShellChannel(sshConnection, response);
262: } else if (channelType != null
263: && CHANNEL_TYPE_FILE.equals(channelType)) {
264: openFileChannel(sshConnection, response);
265: } else {
266: response.sendRedirect(PAGE_HOME);
267: }
268: } catch (SshConnectException sshConnectException) {
269: if (log.isInfoEnabled())
270: log.info("Connection request failed: "
271: + sshConnectException);
272: session.setErrorMessage(sshConnectException
273: .getMessage());
274: response.sendRedirect(PAGE_HOME);
275: }
276: } else {
277: session.setErrorMessage(error);
278: if (log.isInfoEnabled())
279: log
280: .info("Connection request failed due to input validation error: "
281: + error);
282: response.sendRedirect(PAGE_HOME);
283: }
284: }
285:
286: /**
287: * Handles requests to close an SshConnection.
288: *
289: * @param request
290: * @param response
291: */
292: private void closeConnection(HttpServletRequest request,
293: HttpServletResponse response) throws IOException {
294: log.debug("Close Connection request received.");
295:
296: SshSession sshSession = new SshSession(request);
297:
298: SshConnection sshConnection = getConnection(request, sshSession);
299:
300: // If the sshConnection could not be found, give up.
301: if (sshConnection == null) {
302: sshSession
303: .setErrorMessage("Requested sshConnection could not be found.");
304: } else {
305: // Close the Ssh Connection.
306: String connectionInfo = sshConnection.getConnectionInfo();
307: sshConnection.close();
308: sshSession.removeConnection(connectionInfo);
309: }
310:
311: response.sendRedirect(PAGE_HOME);
312: return;
313: }
314:
315: /**
316: * Handles requests to open a ShellChannel on an existing
317: * SshConnection.
318: *
319: * @param request
320: * @param response
321: */
322: private void openShellChannel(HttpServletRequest request,
323: HttpServletResponse response) throws IOException {
324: log.debug("Open Shell Channel request received.");
325:
326: SshSession sshSession = new SshSession(request);
327:
328: SshConnection connection = getConnection(request, sshSession);
329:
330: // If the connection could not be found, give up.
331: if (connection == null) {
332: sshSession
333: .setErrorMessage("Requested connection could not be found.");
334: response.sendRedirect(PAGE_HOME);
335: }
336: // Try to open a ShellChannel
337: else {
338: openShellChannel(connection, response);
339: }
340: }
341:
342: /**
343: * Handles requests to open a ShellChannel on an existing
344: * SshConnection.
345: *
346: * @param sshConnection
347: * @param response
348: * @throws IOException
349: */
350: private void openShellChannel(SshConnection sshConnection,
351: HttpServletResponse response) throws IOException {
352: try {
353: ShellChannel shellChannel = sshConnection
354: .openShellChannel();
355: response.sendRedirect(shellChannel.getPage());
356: } catch (SshConnectException sshConnectException) {
357: log.warn(
358: "Error opening new ShellChannel for sshConnection: "
359: + sshConnection.getConnectionInfo() + ": "
360: + sshConnectException, sshConnectException);
361: response.sendRedirect(PAGE_HOME);
362: }
363: }
364:
365: /**
366: * Handles requests to open a FileChannel on an existing
367: * SshConnection.
368: *
369: * @param request
370: * @param response
371: */
372: private void openFileChannel(HttpServletRequest request,
373: HttpServletResponse response) throws IOException {
374: log.debug("Open File Channel request received.");
375:
376: SshSession sshSession = new SshSession(request);
377:
378: SshConnection connection = getConnection(request, sshSession);
379:
380: // If the connection could not be found, give up.
381: if (connection == null) {
382: sshSession
383: .setErrorMessage("Requested connection could not be found.");
384: response.sendRedirect(PAGE_HOME);
385: }
386: // Try to open a ShellChannel
387: else {
388: openFileChannel(connection, response);
389: }
390: }
391:
392: /**
393: * Handles requests to open a FileChannel on an existing
394: * SshConnection.
395: *
396: * @param sshConnection
397: * @param response
398: * @throws IOException
399: */
400: private void openFileChannel(SshConnection sshConnection,
401: HttpServletResponse response) throws IOException {
402: try {
403: FileChannel fileChannel = sshConnection.openFileChannel();
404: response.sendRedirect(fileChannel.getPage());
405: } catch (SshConnectException sshConnectException) {
406: log.warn(
407: "Error opening new FileChannel for sshConnection: "
408: + sshConnection.getConnectionInfo() + ": "
409: + sshConnectException, sshConnectException);
410: response.sendRedirect(PAGE_HOME);
411: }
412: }
413:
414: /**
415: * Handles requests to open a close an existing channel.
416: *
417: * @param request
418: * @param response
419: */
420: private void closeChannel(HttpServletRequest request,
421: HttpServletResponse response) throws IOException {
422: log.debug("Close Channel request received.");
423:
424: SshSession sshSession = new SshSession(request);
425:
426: SshConnection connection = getConnection(request, sshSession);
427:
428: // If the connection could not be found, give up.
429: if (connection == null) {
430: sshSession
431: .setErrorMessage("Requested connection could not be found.");
432: }
433: // Close a channel.
434: else {
435: String channelId = request.getParameter(PARAMETER_CHANNEL);
436: connection.closeChannel(channelId);
437: }
438:
439: response.sendRedirect(PAGE_HOME);
440: }
441:
442: /**
443: * Returns the SshConnection that is associated with this request, or null
444: * if the session can not be found.
445: *
446: * @param request
447: * @param sshSession
448: * @return the requested SshSession, or null.
449: */
450: private SshConnection getConnection(HttpServletRequest request,
451: SshSession sshSession) {
452: String connectionInfo = request
453: .getParameter(PARAMETER_CONNECTION);
454: SshConnection sshConnection = null;
455: if (connectionInfo != null
456: && connectionInfo.trim().length() > 0) {
457: sshConnection = sshSession.getSshConnection(connectionInfo);
458: }
459:
460: return sshConnection;
461: }
462:
463: private String getParameter(List multiPartItems,
464: String parameterName) {
465: Iterator iter = multiPartItems.iterator();
466: while (iter.hasNext()) {
467: FileItem fileItem = (FileItem) iter.next();
468: if (fileItem.isFormField()) {
469: if (parameterName.equals(fileItem.getFieldName())) {
470: return fileItem.getString();
471: }
472: }
473: }
474: return null;
475: }
476:
477: private FileItem getFile(List multiPartItems) {
478: Iterator iter = multiPartItems.iterator();
479: while (iter.hasNext()) {
480: FileItem fileItem = (FileItem) iter.next();
481: if (!fileItem.isFormField()) {
482: return fileItem;
483: }
484: }
485: return null;
486: }
487: }
|