/*******************************************************************************
* Copyright (c) 2011, 2016 Eurotech and/or its affiliates
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eurotech
*******************************************************************************/
package org.eclipse.kura.web.server;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.eclipse.kura.web.shared.GwtKuraErrorCode;
import org.eclipse.kura.web.shared.GwtKuraException;
import org.eclipse.kura.web.shared.model.GwtXSRFToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class KuraRemoteServiceServlet extends RemoteServiceServlet {
/**
*
*/
private static final long serialVersionUID = 3473193315046407200L;
private static Logger s_logger = LoggerFactory.getLogger(KuraRemoteServiceServlet.class);
/**
*
* If the given xsrfToken is not valid a GwtEdcException will throw.
* Check if the given xsrfToken is valid, otherwise traces the user network info and invalidates the user session.
*
* @param xsrfToken
* @throws GwtEdcException
*/
public void checkXSRFToken(GwtXSRFToken xsrfToken) throws GwtKuraException {
HttpServletRequest req = this.perThreadRequest.get();
performXSRFTokenValidation(req, xsrfToken);
}
/**
*
* This method perform a XSRF validation on the given request and for the specific userToken.
* This is a private method to support both, standard class validation or multipart Servlet validation.
*
* @param req
* @param userToken
*/
static private void performXSRFTokenValidation(HttpServletRequest req, GwtXSRFToken userToken)
throws GwtKuraException {
HttpSession session = req.getSession();
if (!isValidXSRFToken(session, userToken)) {
if (session != null) {
s_logger.info("XSRF token is NOT VALID - Token={}", userToken.getToken());
s_logger.debug("\tSender IP: {}", req.getRemoteAddr());
s_logger.debug("\tSender Host: {}", req.getRemoteHost());
s_logger.debug("\tSender Port: {}", req.getRemotePort());
s_logger.debug("\tFull Request URL\n {}?{}\n\n", req.getRequestURL().toString(), req.getQueryString());
}
// forcing the console log out
session.invalidate();
s_logger.debug("Session invalidated.");
throw new GwtKuraException(GwtKuraErrorCode.INTERNAL_ERROR, null, "Invalid XSRF token");
}
}
/**
*
* Verify if the given userToken is valid on the given session.
* This method tests if the server xsrf token is equals on the user token.
* If yes, the method returns true, otherwise returns false.
* This method controls the xsrf token date validity based on the expire date field.
*
* @param session
* @param userToken
* @return boolean
*/
static public boolean isValidXSRFToken(HttpSession session, GwtXSRFToken userToken) {
s_logger.debug("Starting XSRF Token validation...'");
if (userToken == null) {
s_logger.debug("XSRF Token is NOT VALID -> NULL TOKEN");
return false;
}
// Retrieve the server side token
GwtXSRFToken serverXSRFToken = (GwtXSRFToken) session.getAttribute(GwtSecurityTokenServiceImpl.XSRF_TOKEN_KEY);
if (serverXSRFToken != null) {
String serverToken = serverXSRFToken.getToken();
// Checking the XSRF validity on the serverToken
if (isValidStringToken(serverToken)) {
if (isValidStringToken(userToken.getToken())) {
if (serverToken.equals(userToken.getToken())) {
// Checking expire date
if (new Date().before(userToken.getExpiresOn())) {
s_logger.debug("XSRF Token is VALID - {}", userToken.getToken());
// Reset used token
session.setAttribute(GwtSecurityTokenServiceImpl.XSRF_TOKEN_KEY, null);
return true;
} else {
session.setAttribute(GwtSecurityTokenServiceImpl.XSRF_TOKEN_KEY, null);
s_logger.error("XSRF Token is EXPIRED - {}", userToken.getToken());
}
}
}
}
}
s_logger.debug("XSRF Token is NOT VALID - {}", userToken.getToken());
return false;
}
/**
*
* Performs some basic string validation on the given String token.
*
* @param token
* @return boolean
*/
static private boolean isValidStringToken(String token) {
if (token != null) {
if (!token.isEmpty()) {
return true;
}
}
return false;
}
/**
*
* Get the given value field from the Servlet request if exist.
* Returns null if the passed fieldName isn't present in the request.
*
* @param req
* @param fieldName
* @return String
* @throws Exception
*/
@SuppressWarnings("unchecked")
static public String getFieldFromMultiPartForm(HttpServletRequest req, String fieldName) throws Exception {
String fieldValue = null;
ServletFileUpload upload = new ServletFileUpload();
List<FileItem> items = upload.parseRequest(req);
// Process the uploaded items
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next();
if (item.isFormField()) {
String name = item.getFieldName();
if (name.equals(fieldName)) {
fieldValue = item.getString();
s_logger.debug("Found field name '{}' with value: {}", name, fieldValue);
}
}
}
return fieldValue;
}
static public void checkXSRFToken(HttpServletRequest req, GwtXSRFToken token) throws Exception {
performXSRFTokenValidation(req, token);
}
/**
*
* Check if the given xsrfToken is valid, otherwise traces the user network info and invalidates the user session.
* This is the checkXSRFToken for the MultiPart Servlet support.
*
* @param req
* @throws Exception
*/
static public void checkXSRFTokenMultiPart(HttpServletRequest req, GwtXSRFToken token) throws Exception {
performXSRFTokenValidation(req, token);
}
}