package org.opentosca.csarrepo.servlet;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.jersey.internal.util.Base64;
import org.opentosca.csarrepo.exception.AuthenticationException;
import org.opentosca.csarrepo.model.User;
import org.opentosca.csarrepo.service.LoadCheckedUserService;
import org.opentosca.csarrepo.service.LoadUserService;
import org.opentosca.csarrepo.util.Hash;
import org.opentosca.csarrepo.util.PlanInvocationHelper;
import org.opentosca.csarrepo.util.StringUtils;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateHashModel;
import freemarker.template.TemplateModelException;
/**
* Abstraction for the servlet implementations
*
* @author eiselems (marcus.eisele@gmail.com), Thomas Kosch
* (mail@thomaskosch.com), Dennis Przytarski
*
*/
@SuppressWarnings("serial")
public abstract class AbstractServlet extends HttpServlet {
private static final String ERRORS = "errors";
private static final String SUCCESSES = "successes";
private static final Logger LOGGER = LogManager.getLogger(AbstractServlet.class);
private Configuration cfg = new Configuration(Configuration.VERSION_2_3_21);
/**
* @see HttpServlet#HttpServlet()
*/
public AbstractServlet() {
super();
cfg.setDefaultEncoding("UTF-8");
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
}
/**
* This method is overloaded to implement the get functionality
*
* !Don't forget to invoke prepareServlet before doing anything with the
* template!
*
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
@Override
protected abstract void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException;
public Map<String, Object> getRoot(HttpServletRequest request) throws ServletException {
Map<String, Object> root = new HashMap<String, Object>();
root.put("basePath", this.getBasePath());
try {
BeansWrapper beansWrapper = new BeansWrapperBuilder(Configuration.VERSION_2_3_21).build();
TemplateHashModel staticModels = beansWrapper.getStaticModels();
TemplateHashModel stringUtils = (TemplateHashModel) staticModels.get(StringUtils.class.getCanonicalName());
TemplateHashModel planInvocationHelper = (TemplateHashModel) staticModels.get(PlanInvocationHelper.class
.getCanonicalName());
root.put("StringUtils", stringUtils);
root.put("PlanInvocationHelper", planInvocationHelper);
} catch (TemplateModelException e) {
throw new ServletException(e);
}
root.put(ERRORS, request.getSession().getAttribute(ERRORS));
root.put(SUCCESSES, request.getSession().getAttribute(SUCCESSES));
request.getSession().setAttribute(ERRORS, new ArrayList<String>());
request.getSession().setAttribute(SUCCESSES, new ArrayList<String>());
return root;
}
/**
* @return the base path of the repository <code>/csarrepo</code>
*/
public String getBasePath() {
return this.getServletContext().getContextPath();
}
/**
* Triggers authentication over HTTP
*
* @param request
* The incoming request for the servlet
* @param response
* The outgoing response of the servlet
* @return The user
* @throws IOException
*/
public User checkBasicAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
// Basic authentication for REST API
if (null != request.getHeader("Authorization")) {
String header = request.getHeader("Authorization");
if (header.substring(0, 6).equals("Basic ")) {
String[] credentials = Base64.decodeAsString(header.substring(6).getBytes()).split(":");
if (credentials.length > 1) {
String username = credentials[0];
String password = credentials[1];
String hashedPassword = Hash.sha256(password);
LoadCheckedUserService loadCheckedUserService = new LoadCheckedUserService(username, hashedPassword);
if (!loadCheckedUserService.hasErrors()) {
return loadCheckedUserService.getResult();
} else {
// TODO: log more than one error
LOGGER.error(StringUtils.join(loadCheckedUserService.getErrors()));
response.sendError(401);
}
}
}
}
LOGGER.info("Basic Authorization: Invalid credentials");
response.sendError(401);
return null;
}
/**
* This method uses the <code>request</code> session attribute <i>user</i>
* to find the matching user.
*
* If no user is found it alters the given <code>request</code> to redirect
* to the login page.
*
* @param request
* The incoming request for the servlet
* @param response
* The outgoing response
* @return the user
*
* @throws AuthenticationException
* if the user doesn't exist
* @throws IOException
*/
public User checkUserAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException,
AuthenticationException {
HttpSession session = request.getSession(false);
if (null != session && null != session.getAttribute("user") && session.getAttribute("user") instanceof User
&& (null != new LoadUserService(((User) session.getAttribute("user")).getId()).getResult())) {
return (User) session.getAttribute("user");
} else {
LOGGER.info("User object does not exist!");
response.sendRedirect(getBasePath() + LoginServlet.PATH);
throw new AuthenticationException("User object does not exist!");
}
}
/**
* @param sc
* @param templateName
* @throws IOException
*/
public Template getTemplate(ServletContext sc, String templateName) throws IOException {
cfg.setDirectoryForTemplateLoading(new File(this.getServletContext().getRealPath("/")));
return cfg.getTemplate(templateName);
}
/**
* Wrapper method for redirecting responses with concatenation of the
* session id.
*
* @param request
* The servlet request
* @param response
* The servlet response
* @param redirectPath
* The redirect path
* @throws IOException
*/
protected void redirect(HttpServletRequest request, HttpServletResponse response, String redirectPath)
throws IOException {
response.sendRedirect(String.format("%s%s;jsessionid=%s", getBasePath(), redirectPath, request.getSession()
.getId()));
}
protected static boolean hasErrors(HttpServletRequest request) {
List<String> errors = (List<String>) request.getSession().getAttribute(ERRORS);
return errors.size() > 0;
}
/**
* Get notification errors from the request.
*
* @param request
* @return List of errors
*/
protected static List<String> getErrors(HttpServletRequest request) {
return (List<String>) request.getSession().getAttribute(ERRORS);
}
/**
* Add an error to the error notification list.
*
* @param request
* where the error should be added
* @param error
*/
protected static void addError(HttpServletRequest request, String error) {
((List<String>) request.getSession().getAttribute(ERRORS)).add(error);
}
/**
* Add an existing error list to the error notification list.
*
* @param request
* where the errors should be added
* @param errors
*/
protected static void addErrors(HttpServletRequest request, List<String> errors) {
((List<String>) request.getSession().getAttribute(ERRORS)).addAll(errors);
}
/**
* Get notification successes from the request.
*
* @param request
* @return List of successes
*/
protected static List<String> getSuccesses(HttpServletRequest request) {
return (List<String>) request.getSession().getAttribute(SUCCESSES);
}
/**
* Add a success to the success notification list.
*
* @param request
* where the success should be added
* @param success
*/
protected static void addSuccess(HttpServletRequest request, String success) {
((List<String>) request.getSession().getAttribute(SUCCESSES)).add(success);
}
/**
* Add an existing success list to the success notification list.
*
* @param request
* where the successes should be added
* @param successes
*/
protected static void addSuccesses(HttpServletRequest request, List<String> successes) {
((List<String>) request.getSession().getAttribute(SUCCESSES)).addAll(successes);
}
}