All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src-main.org.awakefw.file.servlet.ServerAwakeFileDispatch Maven / Gradle / Ivy

Go to download

Awake FILE is a secure Open Source framework that allows to program very easily file uploads/downloads and RPC through http. File transfers include powerful features like file chunking and automatic recovery mechanism. Security has been taken into account from the design: server side allows to specify strong security rules in order to protect the files and to secure the RPC calls.

There is a newer version: 3.0
Show newest version
/*
 * This file is part of Awake FILE. 
 * Awake FILE: Easy file upload & download over HTTP with Java.                                    
 * Copyright (C) 2014,  KawanSoft SAS
 * (http://www.kawansoft.com). All rights reserved.                                
 *                                                                               
 * Awake FILE is free software; you can redistribute it and/or                 
 * modify it under the terms of the GNU Lesser General Public                    
 * License as published by the Free Software Foundation; either                  
 * version 2.1 of the License, or (at your option) any later version.            
 *                                                                               
 * Awake FILE is distributed in the hope that it will be useful,               
 * but WITHOUT ANY WARRANTY; without even the implied warranty of                
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             
 * Lesser General Public License for more details.                               
 *                                                                               
 * You should have received a copy of the GNU Lesser General Public              
 * License along with this library; if not, write to the Free Software           
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
 * 02110-1301  USA
 *
 * Any modifications to this file must keep this entire header
 * intact.
 */
package org.awakefw.file.servlet;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.logging.Level;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.awakefw.commons.api.server.AwakeCommonsConfigurator;
import org.awakefw.commons.server.util.AwakeServerLogger;
import org.awakefw.file.api.server.AwakeFileConfigurator;
import org.awakefw.file.api.server.fileaction.AwakeFileActionManager;
import org.awakefw.file.api.util.AwakeDebug;
import org.awakefw.file.api.util.HtmlConverter;
import org.awakefw.file.json.ListOfStringTransport;
import org.awakefw.file.servlet.util.CallUtil;
import org.awakefw.file.util.StringUtil;
import org.awakefw.file.util.Tag;
import org.awakefw.file.util.TransferStatus;
import org.awakefw.file.util.parms.Action;
import org.awakefw.file.util.parms.Parameter;
import org.awakefw.file.util.parms.ReturnCode;
import org.awakefw.file.version.AwakeFileVersionValues;

/**
 * @author Nicolas de Pomereu
 * 
 *         The method executeRequest() is to to be called from the
 *         ServerCallerRecv Servlet and Class. 
* It will execute a client side request with a ServerCaller.call() * instance. * */ public class ServerAwakeFileDispatch { private static boolean DEBUG = AwakeDebug .isSet(ServerAwakeFileDispatch.class); // A space public static final String SPACE = " "; public static String CR_LF = System.getProperty("line.separator"); /** * Constructor */ public ServerAwakeFileDispatch() { } /** * * Execute the dispatched request * * @param request * the http request * @param response * the http response * @param servletContextTempDir * The temp dir used by Servlets * @param awakeCommonsConfigurator * the client commons configurator * @param awakeFileConfigurator * the client configurator for files * @param awakeFileActionManager * the client instance for File actions * @throws IOException * if any Servlet Exception occurs */ public void executeRequest(HttpServletRequest request, HttpServletResponse response, File servletContextTempDir, AwakeCommonsConfigurator awakeCommonsConfigurator, AwakeFileConfigurator awakeFileConfigurator, AwakeFileActionManager awakeFileActionManager) throws IOException { OutputStream out = null; try { // Immediate catch if we are asking a file upload, because // parameters are // in unknown sequence. We know it's a upload action if it's mime // multipart if (ServletFileUpload.isMultipartContent(request)) { ServerFileUploadAction serverFileUploadAction = new ServerFileUploadAction(); serverFileUploadAction.executeAction(request, response, servletContextTempDir, awakeCommonsConfigurator, awakeFileConfigurator, awakeFileActionManager); return; } debug("ServerAwakeFileDispatch begin 2"); // The action & filename (for file size ask) String action = null; // We must trap the IllegalArgumentException to rethrow properly to // client // This happens if there is an encryption problem try { action = request.getParameter(Parameter.ACTION); } catch (IllegalArgumentException e) { out = response.getOutputStream(); throw e; } action = StringUtil.getTrimValue(action); debug("ACTION : " + action); // Special action for Login, because Token does not exists and must // be built if (action.equals(Action.LOGIN_ACTION) || action.equals(Action.BEFORE_LOGIN_ACTION)) { ServerLoginAction serverLoginAction = new ServerLoginAction(); serverLoginAction.executeAction(request, response, awakeCommonsConfigurator, action); return; } out = response.getOutputStream(); // Only if there is a call action, we may execute authorized classes // without authentication/login if (action.equals(Action.CALL_ACTION) || action.equals(Action.CALL_ACTION_HTML_ENCODED)) { // The class name String methodName = request.getParameter(Parameter.METHOD_NAME); methodName = StringUtil.getTrimValue(methodName); String className = StringUtils.substringBeforeLast(methodName, "."); Class c = Class.forName(className); CallUtil callUtil = new CallUtil(c); boolean callAllowed = callUtil.isCallableNotAuthenticated(); if (callAllowed) { if (action.equals(Action.CALL_ACTION) || action.equals(Action.CALL_ACTION_HTML_ENCODED)) { ServerCallAction serverCallAction = new ServerCallAction(); serverCallAction.call(request, awakeCommonsConfigurator, awakeFileConfigurator, out, null); } return; } } // For all other actions, we check the parameters // The username (used for token re-compilation) String username = request.getParameter(Parameter.USERNAME); username = StringUtil.getTrimValue(username); debug("username : " + username); // // For old call(): // try { // username = StringUtil.fromBase64(username); // } catch (Exception e) { // } // The login may be in clear // Authentication Token with SHA-1(login + secret value) String token = request.getParameter(Parameter.TOKEN); token = StringUtil.getTrimValue(token); if (!ServerAwakeFileDispatch.isTokenValid(username, token, awakeCommonsConfigurator)) { debug("invalid token!"); debug("username: " + username); debug("token : " + token); writeLine(out, TransferStatus.SEND_OK); writeLine(out, ReturnCode.INVALID_LOGIN_OR_PASSWORD); return; } // Notify to Kawan in async mode using a secured Thread that // the user has successfully logged (done once in JVM session per // username). // No notification is done if user.home/.awake/no_notify.txt exists // or web server name is localhost or 127.0.0.1 if (!KawanNotifier.existsNoNotifyTxt() && !KawanNotifier.usernameAlreadyLogged(username) && !KawanNotifier.serverNameIsLocalhost()) { KawanNotifier kawanNotifier = new KawanNotifier(username, "AwakeFile_" + AwakeFileVersionValues.VERSION); kawanNotifier.start(); } // The filename String filename = request.getParameter(Parameter.FILENAME); filename = StringUtil.getTrimValue(filename); // Treat all actions if (action.equals(Action.DELETE_FILE_ACTION)) { boolean result = awakeFileActionManager.delete( awakeFileConfigurator, username, filename); writeLine(out, TransferStatus.SEND_OK); writeLine(out, "" + result); } else if (action.equals(Action.EXISTS_ACTION)) { boolean result = awakeFileActionManager.exists( awakeFileConfigurator, username, filename); writeLine(out, TransferStatus.SEND_OK); writeLine(out, "" + result); } else if (action.equals(Action.MKDIR_ACTION)) { boolean result = awakeFileActionManager.mkdir( awakeFileConfigurator, username, filename); writeLine(out, TransferStatus.SEND_OK); writeLine(out, "" + result); } else if (action.equals(Action.MKDIR_ACTION)) { boolean result = awakeFileActionManager.mkdir( awakeFileConfigurator, username, filename); writeLine(out, TransferStatus.SEND_OK); writeLine(out, "" + result); } else if (action.equals(Action.MKDIRS_ACTION)) { boolean result = awakeFileActionManager.mkdirs( awakeFileConfigurator, username, filename); writeLine(out, TransferStatus.SEND_OK); writeLine(out, "" + result); } else if (action.equals(Action.LIST_DIRS_IN_DIR_ACTION) || action.equals(Action.LIST_FILES_IN_DIR_ACTION)) { actionListDirsOrFiles(awakeFileConfigurator, awakeFileActionManager, username, filename, action, out); } else if (action.equals(Action.GET_FILE_LENGTH_ACTION)) { long result = actionGetListFileLength(awakeFileConfigurator, awakeFileActionManager, username, filename); writeLine(out, TransferStatus.SEND_OK); writeLine(out, Long.toString(result)); } else if (action.equals(Action.DOWNLOAD_FILE_ACTION)) { boolean result = awakeFileActionManager.download(out, awakeFileConfigurator, username, filename); if (!result) { // Impossible to find the file on server writeLine(out, TransferStatus.SEND_OK); writeLine(out, Tag.FileNotFoundException); // throw new FileNotFoundException( // "File not found on remote server: " + filename); } } else if (action.equals(Action.CALL_ACTION) || action.equals(Action.CALL_ACTION_HTML_ENCODED)) { ServerCallAction serverCallAction = new ServerCallAction(); serverCallAction.call(request, awakeCommonsConfigurator, awakeFileConfigurator, out, username); } else { throw new IllegalArgumentException("Invalid Client Action: " + action); } return; } catch (Exception e) { writeLine(out, TransferStatus.SEND_FAILED); writeLine(out, e.getClass().getName()); // Exception class name writeLine(out, ServerUserException.getMessage(e)); // Exception // message writeLine(out, ExceptionUtils.getStackTrace(e)); // stack trace try { AwakeServerLogger.log(Level.WARNING, Tag.AWAKE_EXCEPTION_RAISED + ServerUserException.getMessage(e)); AwakeServerLogger.log(Level.WARNING, Tag.AWAKE_EXCEPTION_RAISED + ExceptionUtils.getStackTrace(e)); } catch (Exception e1) { e1.printStackTrace(); e1.printStackTrace(System.out); } } } /** * Write a line of string on the servlet output stream. Will add the * necessary CR_LF * * @param out * the servlet output stream * @param s * the string to write * @throws IOException */ private void writeLine(OutputStream out, String s) throws IOException { out.write((s + CR_LF).getBytes()); } /** * Check the validity of the (username, token) pair
* Will return false if the operation is now allowed! * * @param username * the username to check * @param token * the associated token with the username * @param awakeCommonsConfigurator * the user configuration * * @return true if the pair (username, token) is verified and ok. * @throws Exception */ public static boolean isTokenValid(String username, String token, AwakeCommonsConfigurator awakeCommonsConfigurator) throws Exception { // OK! Now build a token with SHA-1(username + secretValue) String tokenRecomputed = AwakeCommonsConfiguratorCall.computeAuthToken( awakeCommonsConfigurator, username); if (token == null || !token.equals(tokenRecomputed)) { debug("username : " + username + ":"); debug("token : " + token + ":"); debug("tokenRecomputed: " + tokenRecomputed + ":"); return false; } return true; } /** * Action: List all sub-directories in a directory * * @param awakeFileConfigurator * the user configuration * @param awakeFileActionManager * the user file manager * @param username * the client login * @param filename * the full path of directory to list files od directory * @param out * the output stream * @throws IOException */ private void actionListDirsOrFiles( AwakeFileConfigurator awakeFileConfigurator, AwakeFileActionManager awakeFileActionManager, String username, String filename, String action, OutputStream out) throws IOException { debug("actionListDirsOrFiles: " + action); List files = null; if (action.equals(Action.LIST_FILES_IN_DIR_ACTION)) { files = awakeFileActionManager.listFiles(awakeFileConfigurator, username, filename); } else if (action.equals(Action.LIST_DIRS_IN_DIR_ACTION)) { files = awakeFileActionManager.listDirectories( awakeFileConfigurator, username, filename); } else { throw new IllegalArgumentException(Tag.AWAKE_PRODUCT_FAIL + "Invalid list dirs/files action: " + action); } if (files == null) { writeLine(out, TransferStatus.SEND_OK); writeLine(out, null); return; } if (files.size() == 0) { writeLine(out, TransferStatus.SEND_OK); writeLine(out, files.toString()); // [] return; } writeLine(out, TransferStatus.SEND_OK); for (File file : files) { String theFile = file.getName(); theFile = HtmlConverter.toHtml(theFile); writeLine(out, theFile); } } /** * Action: delete a file list * * @param awakeFileConfigurator * @param awakeFileActionManager * * @param filename * the filelist */ private long actionGetListFileLength( AwakeFileConfigurator awakeFileConfigurator, AwakeFileActionManager awakeFileActionManager, String username, String filename) throws IOException { debug("Action.GET_FILE_LENGTH_ACTION"); long result = 0; // We have in fact a list of files List files = ListOfStringTransport.fromJson(filename); // actionGetListFileLength: We must convert each element of List // files from Html files = HtmlConverter.fromHtml(files); for (String theFilename : files) { result += awakeFileActionManager.length(awakeFileConfigurator, username, theFilename); } return result; } private static void debug(String s) { if (DEBUG) { AwakeServerLogger.log(s); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy