PathFilter.java
package sk.iway.iwcm;
import org.apache.commons.codec.binary.Base64;
import org.apache.struts.util.TokenProcessor;
import org.springframework.web.util.NestedServletException;
import sk.iway.iwcm.analytics.AnalyticsHelper;
import sk.iway.iwcm.common.*;
import sk.iway.iwcm.components.abtesting.ABTesting;
import sk.iway.iwcm.components.domainRedirects.DomainRedirectDB;
import sk.iway.iwcm.components.response_header.rest.ResponseHeaderService;
import sk.iway.iwcm.dmail.Sender;
import sk.iway.iwcm.doc.DebugTimer;
import sk.iway.iwcm.doc.DocDB;
import sk.iway.iwcm.doc.DocDetails;
import sk.iway.iwcm.doc.GroupDetails;
import sk.iway.iwcm.doc.ShowDoc;
import sk.iway.iwcm.doc.ninja.Ninja;
import sk.iway.iwcm.filebrowser.EditForm;
import sk.iway.iwcm.i18n.Prop;
import sk.iway.iwcm.io.*;
import sk.iway.iwcm.stat.BrowserDetector;
import sk.iway.iwcm.stat.SessionHolder;
import sk.iway.iwcm.stat.StatDB;
import sk.iway.iwcm.system.WJResponseWrapper;
import sk.iway.iwcm.system.context.ContextFilter;
import sk.iway.iwcm.system.ntlm.AuthenticationFilter;
import sk.iway.iwcm.system.stripes.CSRF;
import sk.iway.iwcm.users.UsersDB;
import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.PageContext;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.*;
/**
* Filter premapovava volania na virtualne adresare a stranky do volani na
* spravne docid
*
* @Title WebJET
* @Company Interway s.r.o. (www.interway.sk)
* @Copyright Interway s.r.o. (c) 2001-2002
* @author Craig McClanahan
* @version $Revision: 1.4 $ $Date: 2004/03/01 17:03:45 $
* @created Nede?e, 2002, okt?ber 27
* @modified $Date: 2004/03/01 17:03:45 $
*/
@SuppressWarnings("java:S1075")
public class PathFilter implements Filter
{
private static final String CHECK_ADMIN_SESSION_KEY = "pathFilter.checkAdmin";
private static final String CHECK_WEB_ACCESS_SESSION_KEY = "pathFilter.checkWebAccess";
private static final String CHECK_DOMAIN_SESSION_KEY = "pathFilter.checkDomain";
private static String customPath = null;
private static Map<String, EditForm> passwordProtected;
public static final String REQUEST_START_TIME = "pathFilet.requestStartTime";
private static String[] bypassPath = null;
//pocet sekund cache pre staticky obsah
private static int cacheStaticContentSeconds = -1;
private static String[] cacheStaticContentSuffixes = null;
private static List<ResponseHeaderBean> responseHeaders;
private static Map<String, DynamicForward> dynamicForwards;
/**
* Inicializacia servletu
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
//tu nemozeme pouzivat logger pretoze toto sa vola skor ako zbehne InitServlet
Logger.info(PathFilter.class, "PathFilter init");
try
{
//inicializuj password protected
//robime az v doFilter reloadProtectedDirs();
PathFilter.setCustomPath(filterConfig.getInitParameter("customPath"));
//aby bolo mozne nastavit aj cez -Dwebjet.customPath=...
String systemParam = System.getProperty("webjet.customPath");
if (Tools.isNotEmpty(systemParam)) PathFilter.setCustomPath(systemParam);
prepareTemplates();
}
catch (Exception e)
{
sk.iway.iwcm.Logger.error(e);
}
}
public static void registerDynamicForward(String name, DynamicForward dynamicForward)
{
if (dynamicForwards==null) dynamicForwards = Collections.synchronizedMap(new HashMap<String, DynamicForward>());
dynamicForwards.put(name, dynamicForward);
}
public static void unregisterDynamicForward(String name)
{
if (dynamicForwards==null) return;
if (dynamicForwards.containsKey(name)) dynamicForwards.remove(name);
}
public static void prepareTemplates()
{
if (Tools.isNotEmpty(customPath))
{
//tu nemozeme pouzivat logger pretoze toto sa vola skor ako zbehne InitServlet
Logger.info(PathFilter.class, "PathFilterInit - customPath: " + customPath + File.separatorChar + Constants.getInstallName());
//skopiruj templates do custom adresara
File templatesDir = new File(customPath + File.separatorChar + Constants.getInstallName() + File.separatorChar
+ "/templates/");
if (templatesDir.exists())
{
File f;
f = new File(Tools.getRealPath("/templates/" + Constants.getInstallName() + "/"));
if (f.exists() == false)
{
//vytvor adresar
if(f.mkdirs() == false) return;
}
File[] listFiles = templatesDir.listFiles();
int size = listFiles.length;
int i;
File outFile;
for (i = 0; i < size; i++)
{
f = listFiles[i];
//Logger.println(this,"copy: " + f.getName());
outFile = new File(Tools.getRealPath(
"/templates/" + Constants.getInstallName() + "/" + f.getName()));
if (outFile.exists() == false || outFile.lastModified() < f.lastModified())
{
//skopiruj subory
FileTools.copyFile(f, outFile);
}
}
}
}
}
public static String getCustomPath()
{
return(customPath);
}
/**
* Vrati REAL PATH pre zadane URL aj s detekciou Custom Path (pouzitelne len pre staticke subory)
* @param url
* @return
*/
public static String getCustomPathRealPath(String url)
{
String realPath = PathFilter.getRealPath(url);
if (PathFilter.getCustomPath() != null)
{
//skontroluj, ci pozadovany subor nie je custom
IwcmFile fCusom = new IwcmFile(PathFilter.getCustomPath() + File.separatorChar + Constants.getInstallName() + url.replace('/', File.separatorChar));
if (fCusom.exists() && fCusom.canRead()) realPath = fCusom.getAbsolutePath();
}
return realPath;
}
/**
* Take this filter out of service.
*/
@Override
public void destroy()
{
//
}
/**
* Select and set (if specified) the character encoding to be used to
* interpret request parameters for this request.
*
* @param chain
* The filter chain we are processing
* @exception IOException
* if an input/output error occurs
* @exception ServletException
* if a servlet error occurs
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException
{
String path = null;
DebugTimer timer = null;
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse res = (HttpServletResponse) servletResponse;
try
{
if (passwordProtected==null) reloadProtectedDirs();
//System.out.println("PathFilter.doFilter: "+servletRequest.getClass());
//System.out.println("PathFilter.doFilter: "+(servletRequest instanceof HttpServletRequest));
//req.setCharacterEncoding("windows-1250");
//req.setAttribute("SetCharacterEncodingFilter.encoding", "windows-1250");
path = req.getRequestURI();
if (Tools.isNotEmpty(req.getContextPath()))
{
path = path.substring(req.getContextPath().length());
}
if (path.contains("//"))
{
path = Tools.replace(path, "/////", "/");
path = Tools.replace(path, "////", "/");
path = Tools.replace(path, "///", "/");
path = Tools.replace(path, "//", "/");
res.setStatus(302);
StringBuilder redir = new StringBuilder();
redir.append(Tools.sanitizeHttpHeaderParam(path));
String qs = req.getQueryString();
if (Tools.isNotEmpty(qs)) redir.append('?').append(qs);
res.setHeader("Location", redir.toString());
//res.sendRedirect(path);
return;
}
//Logger.println(this,"query string PATH FILTER=" + req.getQueryString());
String qs = req.getQueryString();
boolean isFirstPathFilterCall = (req.getAttribute("path_filter_orig_path")==null);
req.setAttribute("path_filter_query_string", qs);
req.setAttribute("path_filter_orig_path", path);
setNginxProxyMode(req, res);
setXFrameOptions(res);
setAccessControlAllowOrigin(path, res);
setXXssProtection(res);
setFeaturePolicy(res);
setXRobotsTagValue(path, res);
setResponseHeaders(path, req, res);
//blokovanie akcie /showdoc.do
if(path.startsWith("/showdoc.do") && !"*".equals(Constants.getString("showDocActionAllowedDocids")))
{
int docId = Tools.getIntValue(req.getParameter("docid"), -1);
Identity user = (Identity)req.getSession().getAttribute(Constants.USER_KEY);
if (Tools.isEmpty(Constants.getString("showDocActionAllowedDocids"))
|| ((user == null || !user.isAdmin()) && path.startsWith("/showdoc.do") && !isShowDocAllowDocId(docId, "showDocActionAllowedDocids")))
{
Adminlog.add(Adminlog.TYPE_CLIENT_SPECIFIC, "Nepovolene pouzitie /showdoc.do docId:"+docId+" showDocActionAllowedDocids : "+ Constants.getString("showDocActionAllowedDocids"), -1, -1);
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
}
if (Constants.getInt("linkType") == Constants.LINK_TYPE_HTML && path.startsWith("/showdoc.do") && isFirstPathFilterCall &&
req.getParameterMap().size()==1 && req.getParameter("docid")!=null )
{
//presmeruj sa na stranku v HTML formate
int docId = Tools.getIntValue(req.getParameter("docid"), -1);
if (docId > 0)
{
DocDB docDB = DocDB.getInstance();
if (InitServlet.isTypeCloud() || (Constants.getBoolean("enableStaticFilesExternalDir") && Constants.getBoolean("multiDomainEnabled")))
{
DocDetails doc = DocDB.getInstance().getBasicDocDetails(docId, true);
if (doc!=null)
{
GroupDetails group = GroupDetails.getById(doc.getGroupId());
//MBO: Ak je zapnuty Cloud, otestuje, ci je dany DOC dostupny pre tuto domenu, ak nie, nevykona redirect ale hodi 404
if (group==null || !group.getDomainName().equals(CloudToolsForCore.getDomainName()))
{
Logger.debug(PathFilter.class, "DOC ID="+docId+" is not allowed for domain "+ CloudToolsForCore.getDomainName());
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
}
}
String redirPath = docDB.getDocLink(docId, req);
if (redirPath.startsWith("/showdoc.do")==false && Tools.isNotEmpty(redirPath))
{
res.setStatus(301);
//zrusene, pridanie domeny je zbytocne a potom to zle presmerovava ak sme na inom ako 80 porte if (redirPath.toLowerCase().startsWith("http")==false) redirPath = Tools.getBaseHref(req)+redirPath;
res.setHeader("Location", redirPath);
//res.sendRedirect(redirPath);
/*if (timer != null) //dead code
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}*/
return;
}
}
}
if (path.indexOf('\'')!=-1 || path.indexOf('"')!=-1 || path.indexOf('\r')!=-1 || path.indexOf('\n')!=-1 ||
path.contains("%0D") || path.contains("%0A") || path.contains("%0d") || path.contains("%0a") || //crlf utok
req.getRequestURI().indexOf("//")!=-1 || path.indexOf('\\')!=-1 || path.indexOf("/../")!=-1)
{
if (DocTools.isXssStrictUrlException(path, "xssProtectionStrictGetUrlException")==false)
{
//je to pokus o XSS: /404.html/'onmouseover=prompt(915761)
Adminlog.add(Adminlog.TYPE_XSS, "XSS path="+path, -1, -1);
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
forwardSafely("/403.jsp", req, res);
return;
}
}
if (Tools.replace(path.toLowerCase(), ";jsessionid", "jsessionid").contains(";"))
{
//utok typu /;/admin/help/search.jsp, povolene je len ;jsessionid
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
//povolenie swagger-ui / defaultnej stranky Apache CXF (/ws)
if (path.contains("/swagger") || path.contains("/v2/api-docs") || path.equals("/ws") || path.equals("/ws/"))
{
boolean swaggerEnabled = Constants.getBoolean("swaggerEnabled");
if (swaggerEnabled)
{
//testni, ci je povoleny aj pre neadmina
if (Constants.getBoolean("swaggerRequireAdmin"))
{
Identity user = UsersDB.getCurrentUser(req);
if (user==null || user.isAdmin()==false) swaggerEnabled = false;
}
}
if (swaggerEnabled==false)
{
Adminlog.add(Adminlog.TYPE_XSS, "Swagger path is not enabled (conf. swaggerEnabled=false), path="+path, -1, -1);
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
}
if (path.contains(".DS_Store") || path.contains("debug.") || path.contains("config.properties"))
{
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
//pred bypass NESMIE byt citany ziaden parameter!!!
if ("true".equals(servletRequest.getAttribute("PathFilter.bypass")))
{
//request ziadno nemodifikujeme
try
{
chain.doFilter(servletRequest, servletResponse);
}
catch (SocketException se)
{
//toto neriesime
}
return;
}
//STRICT XSS FILTER (aplikuje sa na vsetky HTTP poziadavky)
String strictXssRedirect = DocTools.getXssStrictUrlRedirect(req, path, qs);
if (strictXssRedirect != null)
{
res.sendRedirect(strictXssRedirect);
return;
}
req.setAttribute("path_filter_orig_docid", req.getParameter("docid"));
if ("true".equals(req.getHeader("userInServletContext")))
{
Identity user2 = (Identity)Constants.getServletContext().getAttribute(Constants.USER_KEY);
if (user2 != null)
{
LogonTools.setUserToSession(req.getSession(), user2);
req.setAttribute("NO WJTOOLBAR", "true");
}
}
//kontrola IP adries pre web sidlo, ci sa moze zobrazit
if (!checkWebAccess(req, path))
{
Logger.debug(PathFilter.class, "checkWebAccess=false, forbidden access, path="+path+" ip="+Tools.getRemoteIP(req));
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
forwardSafely("/403.jsp", req, res);
return;
}
//kontrola na domenove presmerovania
String serverName = Tools.getServerName(req, false);
String redir = DomainRedirectDB.translate(serverName, path, req.getQueryString(), Tools.isSecure(req));
if (redir != null)
{
res.setStatus(301);
res.setHeader("Location", redir);
return;
}
//System.out.println("PathFilter.doFilter path="+path);
req.setAttribute(REQUEST_START_TIME, System.currentTimeMillis());
Identity user = (Identity)req.getSession().getAttribute(Constants.USER_KEY);
if (path.startsWith("/private/rest/") || path.startsWith("/rest/private/") || path.startsWith("/rest/admin/") || path.startsWith("/websocket/private/") || path.startsWith("/websocket/admin/"))
{
if (user == null || ( user.isAdmin()==false && path.contains("/admin/") ))
{
Logger.debug(PathFilter.class, "Nepovoleny pristup k REST/WS");
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
///// SPRING INTEGRACIA
// ak sa nezacina na /spring (aby sa to necyklilo) a ak je to url ktoru pozna spring, forwardne to na spring servlet
if (dynamicForwards!=null && !dynamicForwards.isEmpty())
{
boolean adminAccessAllowed = checkAccessToAdmin(path, req, res);
boolean privateAccessAllowed = true;
if (path.startsWith("/private") && UsersDB.getCurrentUser(req.getSession())==null) privateAccessAllowed = false;
for (DynamicForward df : dynamicForwards.values())
{
if (df.isValid(path))
{
if (adminAccessAllowed && privateAccessAllowed)
{
boolean returnAfterForward = df.forward(path, req, res);
if (returnAfterForward) return;
}
else
{
//ak nie je user prihlaseny a zacina to na /components a neobsahuje rest, tak posli na 403.jsp kde ho moze redirectnut do admin casti (na logon)
if (path.startsWith("/components") && path.contains("rest")==false)
{
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
forwardSafely("/403.jsp", req, res);
return;
}
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
}
}
//toto musi byt az za Springom, aby pre Spring isli aj ostatne HTTP metody
if (Constants.getBoolean("enableUnsafeHttpMethods") == false && path.contains("/rest")==false)
{
String method = req.getMethod().toUpperCase();
//IE zial robi dotaz na SVG aj ako HEAD, takze to musime mat ako vynimku
if (path.endsWith(".svg") && "HEAD".equals(method)) method = "allowedSVG";
//vynimka pre uptimerobot.com, pouzivaju to v statnej sprave
if ("HEAD".equals(method) || "TRACE".equals(method) || "OPTIONS".equals(method))
{
String userAgent = req.getHeader("User-Agent");
if (Tools.isNotEmpty(userAgent) && userAgent.contains("uptimerobot.com"))
{
method = "allowedUptimerobot";
}
}
if ("HEAD".equals(method) || "TRACE".equals(method) || "OPTIONS".equals(method))
{
//je to pokus o XSS: /404.html/'onmouseover=prompt(915761)
Adminlog.add(Adminlog.TYPE_XSS, "HTTP method not allowed: "+method, -1, -1);
res.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
forwardSafely("/403.jsp", req, res);
return;
}
}
String logLevel = req.getParameter("_logLevel");
if (logLevel != null) {
Logger.setWJLogLevel(logLevel);
}
if (Logger.isLevel(Logger.DEBUG) && path.indexOf("refresher")==-1 && (path.endsWith(".do") || path.endsWith(".jsp") || path.endsWith(".html") || path.endsWith(".js") || path.endsWith(".htc")))
{
if (req.getParameter("showPathFilterTime")!=null || req.getSession().getAttribute("pathFilter.showPathFilterTime")!=null)
{
req.getSession().setAttribute("pathFilter.showPathFilterTime", "true");
timer = new DebugTimer("PathFilter");
}
Logger.debug(PathFilter.class, path);
}
//trackovanie videni emailu
String trackGif = Constants.getString("dmailTrackopenGif");
if(Tools.isNotEmpty(trackGif))
{
if(path.contains(trackGif))
{
int emailId = Tools.getIntValue(req.getParameter("emailId"), -1);
if (emailId > 0)
{
EmailToolsForCore.addStatOpen(emailId);
}
}
}
// url tracking with GA or something else
AnalyticsHelper.track(path, req);
//trackovanie kliknuti na linku v emaile
String dmailStatParamValue = req.getParameter(Constants.getString("dmailStatParam"));
if (Tools.isNotEmpty(dmailStatParamValue))
{
int emailId = Sender.getEmailIdFromClickHash(dmailStatParamValue);
if (emailId > 0)
{
String extURL = req.getParameter("extURL");
if (Tools.isNotEmpty(extURL))
{
if (extURL.toLowerCase().trim().startsWith("http")==false)
{
try
{
String extURL2 = Tools.replace(extURL, "|", "=");
Base64 b64 = new Base64();
extURL = new String(b64.decode(extURL2.getBytes()));
}
catch (Exception e)
{
sk.iway.iwcm.Logger.error(e);
}
}
EmailToolsForCore.addStatClick(emailId, extURL, req.getQueryString(), req, res);
res.sendRedirect(extURL.replaceAll("[\r\n]", ""));
return;
}
else
{
EmailToolsForCore.addStatClick(emailId, path, req.getQueryString(), req, res);
}
}
}
//kontrola jsessionid v URL, vynimka pre .jsessionid. je pre grpd cookie modul kde sa edituje takyto kluc
if (path.toLowerCase().contains("jsessionid") || (req.getQueryString()!=null && req.getQueryString().toLowerCase().contains("jsessionid") && req.getQueryString().toLowerCase().contains(".jsessionid.")==false) || req.isRequestedSessionIdFromURL())
{
String description = "SESSION using jsessionid INVALIDATING, sessionId="+req.getSession().getId()+" req IP="+Tools.getRemoteIP(req);
Logger.error(PathFilter.class, description);
//toto stale hlasi acunetix ovs ako neriesene, toto je pokus o riesenie
req.getSession().invalidate();
req.getSession(true);
String pathFixed = path;
int i = pathFixed.toLowerCase().indexOf(";jsessionid");
if (i > 0) pathFixed = pathFixed.substring(0, i);
i = pathFixed.toLowerCase().indexOf("jsessionid");
if (i > 0) pathFixed = pathFixed.substring(0, i);
res.sendRedirect(pathFixed);
return;
}
SessionHolder holder = SessionHolder.getInstance();
if (
"get".equalsIgnoreCase(req.getMethod())==false ||
(
//for admin apply to all methods
path.contains("/admin/") && !path.contains("/scripts/") &&
(path.contains("/rest/") || path.endsWith(".do") || path.endsWith(".jsp") || path.endsWith(".html") || path.endsWith("/") || path.endsWith(".action"))
) ||
(
path.contains("/rest/")
)
)
{
// setni data pre SessionListener - admin cast (ostatne stranky su az dole)
if (holder.set(req.getSession().getId(), path, req)==false)
{
//nastalo session stealing, spravime redirect aby nenastavali exception v JSP
StringBuilder redirPath = new StringBuilder(path);
if (Tools.isNotEmpty(req.getQueryString())) redirPath.append('?').append(req.getQueryString());
res.sendRedirect(Tools.sanitizeHttpHeaderParam(redirPath.toString()));
return;
}
}
if (path.startsWith("/admin"))
{
boolean ret = checkAdmin(req);
if (!ret)
{
Logger.debug(PathFilter.class, "checkAdmin="+ret+" forwarding to 404.jsp");
//not found posielame aby sa admin cast tvarila akoze vobec neexistuje
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
else
{
// cesta /admin/statchart je tam kvoli generovaniu PDF aby ho bolo mozne unsecure embednut
if (Constants.getBoolean("adminRequireSSL") && Tools.isSecure(req) == false && path.indexOf("/admin/statchart")==-1)
{
String httpsRedirectUrl = PathFilter.getHttpsRedirectUrl(req);
Logger.debug(PathFilter.class, "Redirect (adminRequireSSL): " + httpsRedirectUrl);
res.sendRedirect(httpsRedirectUrl);
return;
}
}
//#37426 CSRF ochrana Struts formularov
if (req.getSession().getAttribute("org.apache.struts.action.TOKEN")==null)
{
//vygeneruj token, kedze struts u nas konci vygenerujem len jeden token do session
TokenProcessor.getInstance().saveToken(req);
}
else if (path.endsWith(".do") && "post".equalsIgnoreCase(req.getMethod()) && (req.getContentType()==null || req.getContentType().contains("multipart")==false))
{
if (DocTools.isXssStrictUrlException(path, "xssProtectionStrictPostUrlException")==false)
{
//validuj token
boolean isTokenValid = TokenProcessor.getInstance().isTokenValid(req, false);
if (isTokenValid == false)
{
Logger.info(PathFilter.class, "Struts token not valid, path="+path);
req.setAttribute("errorText", Prop.getInstance(req).getText("components.csrfError"));
forwardSafely("/components/maybeError.jsp", req, res);
return;
}
}
}
}
if (!checkCSRFToken(path, req)) {
Logger.debug(PathFilter.class, "CSRF token missing - header param X-CSRF-Token");
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
forwardSafely("/403.jsp", req, res);
return;
}
//skus prihlasit usera (ak treba)
if ("true".equals(req.getParameter("doFilterLogon")) || "redir".equals(req.getParameter("doFilterLogon")) || Tools.isNotEmpty(req.getHeader("wjlogontoken")))
{
if (user == null)
{
String username = req.getParameter("username");
String password = req.getParameter("password");
String token = req.getParameter("token");
if (token == null) token = req.getHeader("wjlogontoken");
if (Tools.isEmpty(username) && Tools.isEmpty(password) && Tools.isNotEmpty(token))
{
try
{
//toto je len finta, token zacina na NAHODNY ZNAK aby to nebolo na prvy pohlad base64 automaticky dekodovatelne
token = Tools.replace(token, "|", "=").substring(1);
Base64 b64 = new Base64();
token = new String(b64.decode(token.getBytes()));
int i = token.indexOf(":");
if (i>0)
{
username = token.substring(0, i);
password = token.substring(i+1);
}
}
catch (Exception ex) {}
}
if (Tools.isNotEmpty(username) && Tools.isNotEmpty(password))
{
user = new Identity();
Map<String, String> errors = new Hashtable<>();
sk.iway.iwcm.i18n.Prop prop = sk.iway.iwcm.i18n.Prop.getInstance(Constants.getServletContext(), req);
String forward = LogonTools.logon(username, password, user, errors, req, prop);
if (req.getAttribute("logon.err.noadmin")!=null)
{
//nie je to admin, prihlasme ho ako normalneho usera, ak to zbehne, bude user v session
LogonTools.logonUser(req, username, password);
}
else if (forward.compareTo("logon_ok_admin") != 0 || user == null || user.isAdmin() == false)
{
user = null;
}
else
{
user.setLoginName(username);
user.setPassword(UserTools.PASS_UNCHANGED);
user.setValid(true);
//je korektne prihlaseny
LogonTools.setUserToSession(req.getSession(), user);
req.setAttribute("NO WJTOOLBAR", "true");
}
if ("redir".equals(req.getParameter("doFilterLogon")))
{
res.sendRedirect(path);
return;
}
}
}
}
/*
Kontrola pristupu do admin casti (#10398)
*/
if (!checkAccessToAdmin(path, req, res))
{
if (path.equals("/admin/refresher.jsp") == false && path.equals("/admin/rest/refresher") == false && path.equals("/admin/rest/monitoring/actual") == false)
{
Adminlog.add(Adminlog.TYPE_XSS, "Pouzivatel nema pristup do admin casti, presmerovavam na prihlasenie", -1, -1);
}
//ak je to nieco ako /admin.zip /admin~ /admin_backup tak nepresmeruj ale daj chybu
if (path.startsWith("/admin") && path.indexOf("/", 4)==-1 && path.length()>6) {
Logger.debug(PathFilter.class, "Is file like, forwarding to 404.jsp");
//not found posielame aby sa admin cast tvarila akoze vobec neexistuje
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
//na public node rovno vyhlasme 404, tiez pre nepovolene IP adresy
if ("public".equals(Constants.getString("clusterMyNodeType")) || checkAdmin(req)==false)
{
Logger.debug(PathFilter.class, "Public node, forwarding to 404.jsp");
//not found posielame aby sa admin cast tvarila akoze vobec neexistuje
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
Logger.println(PathFilter.class, "Pouzivatel nema pristup do admin casti, presmerovavam na prihlasenie, path="+path + " allowedUrls="+ Constants.getString("allowAdminUrls"));
LogonTools.saveAfterLogonRedirect(req);
String domainController = AuthenticationFilter.getDomainController();
if (Tools.isNotEmpty(domainController))
{
res.sendRedirect("/ntlm/logon.do?admin=true");
}
else if (path.startsWith("/admin/m/"))
{
res.sendRedirect("/admin/m/logon.jsp");
}
else
{
res.sendRedirect(ContextFilter.addContextPath(req.getContextPath(), "/admin/logon/"));
}
return;
}
if (path.toLowerCase().endsWith(".jsp") || path.endsWith("/"))
{
if (path.startsWith("/images") || path.startsWith("/files") || path.startsWith("/shared"))
{
Logger.debug(PathFilter.class, "Volane JSP z nepovoleneho adresara, path="+path);
//not found posielame aby sa admin cast tvarila akoze vobec neexistuje
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
}
if (path.endsWith(".appcache"))
{
//handlovanie zapnutia online modu pre appcache
String appcacheMode = Tools.getCookieValue(req.getCookies(), "appcacheMode", null);
if ("online".equals(appcacheMode))
{
Cookie c = new Cookie("appcacheMode", "");
c.setPath("/");
c.setMaxAge(-1);
c.setHttpOnly(false);
Tools.addCookie(c, res, req);
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
else if (req.getSession().getAttribute(Constants.USER_KEY)==null)
{
//toto nastane, ked user nie je prihlaseny, nemozeme vtedy poslat obsah suboru, lebo sa nacachuje zoznam ako neprihlaseny user
Logger.debug(PathFilter.class, "User not logged " + path);
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
//skontroluj password protected
EditForm ef = isPasswordProtected(path, req);
if (ef != null && ef.isAccessibleFor(user)==false)
{
if (doFileForbiddenRedirect(ef, user, path, req, res)) return;
}
if (path.contains("admin/") && (path.endsWith(".js") || path.endsWith(".html")))
{
//otestuj, ci existuje JSP nahrada
File f = new File(Tools.getRealPath(path+".jsp"));
if (f.exists() && f.canRead())
{
f = null;
res.setHeader("Pragma","No-Cache");
res.setDateHeader("Expires",0);
res.setHeader("Cache-Control","no-Cache");
Logger.debug(PathFilter.class, "Forwarding: "+path+".jsp");
forwardSafely(path+".jsp", req, res);
return;
}
}
if (path.endsWith(".jsp"))
{
res.setHeader("Pragma","No-Cache");
res.setDateHeader("Expires",0);
res.setHeader("Cache-Control","no-Cache");
}
//nastav kodovanie JS suborom
if (path.indexOf("admin/")==-1 && path.endsWith(".js"))
{
IwcmFile f = new IwcmFile(Tools.getRealPath(path));
//otestuj, ci existuje nahrada
File fNahrada = new File(Tools.getRealPath(path+".jsp"));
if (fNahrada.exists() && fNahrada.canRead())
{
//jsp subor by mal nastavit kodovanie spravne
//f = fNahrada;
//tu nespravime nic, musi sa to sprocesovat ako JSP
}
else
{
IwcmFile fCusom = null;
if (customPath != null)
{
//skontroluj, ci pozadovany subor nie je custom
fCusom = new IwcmFile(customPath + File.separatorChar + Constants.getInstallName() + path.replace('/', File.separatorChar));
if (fCusom.exists() && fCusom.canRead()) f = fCusom;
}
String customUrl = WriteTagToolsForCore.getCustomPageNull(path, req);
if (customUrl != null)
{
fCusom = new IwcmFile(Tools.getRealPath(customUrl));
if (fCusom.exists() && fCusom.canRead()) f = fCusom;
}
if (f.exists() && f.canRead())
{
sk.iway.iwcm.Encoding.setResponseEnc(req, res, "text/javascript");
boolean staticHeadersSet = setStaticContentHeaders(path, user, req, res);
setXRobotsTagValue(path, res);
if (staticHeadersSet && IwcmFsDB.useDBStorage()==false && FileCache.useFileCache())
{
if (writeAndCacheFile(path, res)) return;
}
FilePathTools.writeFileOut(f, req, res);
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
return;
}
}
}
//posielaj admin/v9/dist/ alebo /admin/elFinder adresar ako utf-8
if ((path.startsWith("/admin/v9/dist") || path.startsWith("/admin/elFinder")) && (path.endsWith(".js") || path.endsWith(".css")))
{
IwcmFile f = new IwcmFile(Tools.getRealPath(path));
if (f.exists() && f.canRead())
{
String encoding = "text/javascript";
if (path.endsWith(".css")) encoding = "text/css";
sk.iway.iwcm.Encoding.setResponseEnc(req, res, encoding);
setStaticContentHeaders(path, user, req, res);
setXRobotsTagValue(path, res);
//Logger.debug(PathFilter.class, "Sending DIST file: " + f.getAbsolutePath());
FilePathTools.writeFileOut(f, req, res);
return;
}
}
setDownloadHeaders(path, req, res);
boolean staticHeadersSet = setStaticContentHeaders(path, user, req, res);
if (staticHeadersSet && IwcmFsDB.useDBStorage()==false && FileCache.useFileCache())
{
if (writeAndCacheFile(path, res)) return;
}
//toto standardne Tomcat nepozna, pridame hlavicky podla specky
if (path.endsWith(".woff2") || path.endsWith(".woff"))
{
if (path.endsWith(".woff2")) res.setHeader("Content-Type", "font/woff2");
else res.setHeader("Content-Type", "font/woff");
}
//disable direct call to abtesting variant URL eg. /investicie/abtestvariantb.html for NON admin users
if (path.contains(Constants.getString("ABTestingName")))
{
if (Constants.getBoolean("ABTestingAllowVariantUrl")==false) {
if (user == null || user.isAdmin()==false) {
Logger.debug(PathFilter.class, "ABTesting direct call, not allowed for non admin, forwarding to 404.jsp");
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
} else {
//prefer URL variant instead of cookie value
req.setAttribute("ABTestingPrefferVariantUrl", "true");
}
}
//accessDocId je docId web stranky, ktoru sa zobrazuje, ku ktorej sa pristupuje z verejnej casti sidla, nie admin cast
DocDB docDB = DocDB.getInstance();
String domain = DocDB.getDomain(req);
int accessDocId = -1;
//files adresar musime nechat povoleny kvoli linkam z fulltext indexu (/files/subor.xls.html) a presmerovaniu na subor.xls
if (path.startsWith("/images")==false && path.startsWith("/css")==false && path.startsWith("/jscripts")==false && path.startsWith("/templates")==false)
{
if (Constants.getBoolean("ABTesting")==true)
{
accessDocId = ABTesting.getVirtualPathDocId(path, domain, req, res);
}
else
{
//upravene takto ak nie je vobec abtesting trieda dostupna (napr. v cloude)
accessDocId = docDB.getVirtualPathDocId(path, domain);
}
}
if (accessDocId > 0)
{
//kontrola spravnosti domeny
if (!checkDomain(req))
{
Logger.debug(PathFilter.class, "checkDomain=false, forwarding to 404.jsp");
res.setStatus(HttpServletResponse.SC_NOT_FOUND);
forwardSafely("/404.jsp", req, res);
return;
}
//porovnaj URL a pripadne sprav redirect
String realUrl = docDB.getDocLink(accessDocId, req);
if (realUrl!=null && realUrl.equals(path)==false && !realUrl.contains(Constants.getString("ABTestingName")))
{
//URL so znakom * sa odstranuju, musime specialne skontrolovat
String virtualPath = docDB.getBasicDocDetails(accessDocId, true).getVirtualPath();
if (virtualPath == null || virtualPath.indexOf("*")==-1)
{
Logger.debug(PathFilter.class, "nesedi real URL, redirecting to: "+realUrl);
res.setStatus(301);
if (Tools.isNotEmpty(req.getQueryString())) realUrl += '?'+req.getQueryString();
if (realUrl.toLowerCase().startsWith("http")==false) realUrl = Tools.getBaseHref(req)+realUrl;
res.setHeader("Location", Tools.sanitizeHttpHeaderParam(realUrl));
return;
}
}
// setni data pre SessionListener - customer cast
String lastURL = path;
if (req.getQueryString()!=null)
{
path = path + "?" + req.getQueryString();
}
if (holder.set(req.getSession().getId(), lastURL, req)==false)
{
//nastalo session stealing, spravime redirect aby nenastavali exception v JSP
StringBuilder redirPath = new StringBuilder(path);
if (Tools.isNotEmpty(req.getQueryString())) redirPath.append('?').append(req.getQueryString());
res.sendRedirect(Tools.sanitizeHttpHeaderParam(redirPath.toString()));
return;
}
//akoze skuska ochrany pred chybou Cannot create a session after the response has been committed
if (req.getSession().getAttribute("preventCannotCreateSession")==null)
{
req.getSession().setAttribute("preventCannotCreateSession", "1");
}
//Logger.println(this,"forwarding to docId: " + docId);
StringBuilder url = new StringBuilder("/showdoc.do?docid=").append(accessDocId);
if ("get".equalsIgnoreCase(req.getMethod()))
{
String name;
String[] values;
Enumeration<String> params = req.getParameterNames();
while (params.hasMoreElements())
{
name = params.nextElement();
if (name.equals("docid") || name.equals("password")) continue;
values = req.getParameterValues(name);
for (int i = 0; i < values.length; i++)
{
url.append("&").append(Tools.sanitizeHttpHeaderParam(name)).append('=').append(Tools.sanitizeHttpHeaderParam(values[i]));
}
}
}
Logger.debug(PathFilter.class, "PathFilter, url: " + url + " domain="+domain+" origUrl="+path+" qs="+req.getQueryString());
if (Constants.getInt("linkType") == Constants.LINK_TYPE_HTML || path.endsWith(".php") || path.endsWith(".asp") || path.endsWith(".aspx") || Constants.getBoolean("forwardVirtualPath"))
{
req.setAttribute("docid", Integer.toString(accessDocId));
Logger.debug(PathFilter.class, "forwarding1: req=" + req + " resp="+res);
String packagerMode = Constants.getString("packagerMode");
String packagerModeParam = req.getParameter("_packagerMode");
if (Tools.isNotEmpty(packagerModeParam)) packagerMode = packagerModeParam;
if (Tools.isEmpty(packagerMode) || "none".endsWith(packagerMode))
{
req.getRequestDispatcher("/showdoc.do?docid=" + accessDocId).forward(req, res);
}
else
{
long start = Tools.getNow();
WJResponseWrapper respWrapper = new WJResponseWrapper(res, req);
req.getRequestDispatcher("/showdoc.do?docid=" + accessDocId).forward(req, respWrapper);
StringBuilder htmlCode = new StringBuilder(respWrapper.strWriter.getBuffer().toString());
String fixedHtml = htmlCode.toString();
//moznost prepnutia packagera (pre kazdy pripad)
String packagerModeAttr = (String)req.getAttribute("packagerMode");
if (packagerModeAttr!=null) packagerMode = packagerModeAttr;
//ak je treba posli redirect
if (Tools.isNotEmpty(respWrapper.getRedirectURL())) res.sendRedirect(respWrapper.getRedirectURL());
long end = Tools.getNow();
Logger.debug(PathFilter.class, "Packager: HTML packaging tooks: " + (end-start) + "ms");
//zapis vystup
respWrapper.writeResponseToOriginalOutput(req, fixedHtml);
}
}
else
{
Logger.debug(PathFilter.class, "redirecting: req="+req+" resp="+res);
res.sendRedirect(req.getContextPath() + url.toString());
}
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
return;
}
else
{
if ("/sitemap.xml".equals(path))
{
//nie je definovana stranka s URL /sitemap.xml, priamo forwardnem
//je to tu kvoli cloudu, pretoze do 404.jsp uz dorazi request a nema RequestBean (zjavne sa to vola az po skonceni filtrov)
res.setContentType("text/xml; charset=utf-8");
res.setStatus(HttpServletResponse.SC_OK);
String customPage = WriteTagToolsForCore.getCustomPage("/components/sitemap/google-sitemap.jsp", req);
forwardSafely(customPage, req, res);
return;
}
}
if ((path.startsWith("/components/") || path.startsWith("/templates/")) && path.lastIndexOf('.') > path.lastIndexOf('/') && path.equals("/components/editoricon.gif")==false)
{
try
{
//skus najst nahradu za pozadovanu stranku
String customPage = WriteTagToolsForCore.getCustomPage(path, req);
if (customPage.equals(path)==false)
{
forwardSafely(customPage, req, res);
return;
}
if (path.endsWith("editor_component.jsp"))
{
//over ci existuje, ak nie, pouzi defaultnu
if (WriteTagToolsForCore.isFileExists(path)==false)
{
try
{
//tu mame plne meno povodneho suboru v include
String jspFileName = req.getParameter("jspFileName");
if (jspFileName != null)
{
if (jspFileName.startsWith("!INCLUDE(")) jspFileName = jspFileName.substring(9).trim();
//skus verziu s odstranenou druhou castou, /components/iway/news/editor_component.jsp -> /components/news/editor_component.jsp
String pathBezDruhejCasti = "/components"+path.substring(path.indexOf("/", 13));
if (WriteTagToolsForCore.isFileExists(pathBezDruhejCasti))
{
//mame custom subor, ak ale existuje nastaveny CONF kluc k danemu suboru nepouzijeme
String CONF_KEY = jspFileName.substring(0, jspFileName.lastIndexOf('.')).replace('/', '.').substring(1);
Prop prop = Prop.getInstance(req);
//ak kluc neexistuje pouzijeme
if (prop.getText(CONF_KEY+".conf.propSearchKey").equals(CONF_KEY+".conf.propSearchKey") && prop.getText(CONF_KEY+".conf").equals(CONF_KEY+".conf"))
{
Logger.debug(PathFilter.class, "forwarding to:"+pathBezDruhejCasti);
req.getRequestDispatcher(WriteTagToolsForCore.getCustomPage(pathBezDruhejCasti, req)).forward(req, res);
}
}
}
}
catch (Exception ex)
{
sk.iway.iwcm.Logger.error(ex);
}
req.getRequestDispatcher(WriteTagToolsForCore.getCustomPage("/components/editor_component_universal.jsp", req)).forward(req, res);
return;
}
}
}
catch (RuntimeException e)
{
sk.iway.iwcm.Logger.error(e);
}
}
//podpora custom pluginov v editore - NETREBA uz bereme z dist priecinka
/*if (path.startsWith("/admin/skins/webjet8/ckeditor/dist/plugins/") || path.startsWith("/admin/skins/webjet8/ckeditor/plugins/"))
{
path = Tools.replace(path, "/admin/skins/webjet8/ckeditor/dist/plugins/", "/admin/ckeditor/plugins/");
path = Tools.replace(path, "/admin/skins/webjet8/ckeditor/plugins/", "/admin/ckeditor/plugins/");
String customPage = WriteTagToolsForCore.getCustomPageAdmin(path, req);
if (customPage != null)
{
req.getRequestDispatcher(customPage).forward(req, res);
return;
}
}*/
if (path.endsWith(".php") || path.endsWith(".asp"))
{
//skus najst JSP verziu stranky
String jspPath = path.substring(0, path.length() - 4) + ".jsp";
File jspFile = new File(Tools.getRealPath(jspPath));
if (jspFile.exists())
{
forwardSafely(jspPath, req, res);
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
return;
}
}
if (customPath != null)
{
//skontroluj, ci pozadovany subor nie je custom
IwcmFile f = new IwcmFile(customPath + File.separatorChar + Constants.getInstallName() + path.replace('/', File.separatorChar));
if (f.exists()==false)
{
f = new IwcmFile(Tools.getRealPath("/templates/" + Constants.getInstallName() + "/assets" + path));
}
if (f.exists()==false && path.contains("/admin/docsify/") && "iwcm.interway.sk".equals(req.getServerName()) && user != null && user.isAdmin() && path.contains("..")==false)
{
//je to docsify subor, ten mame inde, musime upravit
f = new IwcmFile(Tools.getRealPath("/"));
f = new IwcmFile(f.getParentFile(), path.substring(6).replace('/', File.separatorChar));
}
//Logger.println(this,"Checking CUSTOM: "+f.getAbsolutePath());
if (f.exists() && f.isFile())
{
//existuje custom subor, posli ho na vystup
if (path.toLowerCase().endsWith(".jsp") || path.toLowerCase().endsWith(".class"))
{
//toto este nevieme, nerob nic
Logger.error(this,"TOTO AKO CUSTOM NEVIEM: " + path);
}
else
{
//Logger.println(this,"sending custom page:
// "+f.getAbsolutePath());
//je to nejaky obrazok, alebo subor, posli na vystup
FilePathTools.writeFileOut(f, req, res);
//Logger.println(this,"Zapisany subor: " + path);
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
return;
}
}
}
if (FilePathTools.isExternalDir(path) && path.startsWith("/files/protected/")==false)
{
//externy adresar pre cloudStaticFilesDir folder
boolean fileWritten = FilePathTools.writeFileOut(path, req, res);
if (fileWritten)
{
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
return;
}
}
//zaslanie fresh suboru pre elfinder (volane len s parametrom v=xxx) po zmene velkosti
//tomcat 8 totiz nejako divne cachuje obrazky a aj ked ho zmenime tak to nepomoze a vrati povodny
if (user != null && user.isAdmin() && req.getParameter("v")!=null)
{
String mimeType = Constants.getServletContext().getMimeType(path.toLowerCase());
if (Tools.isEmpty(mimeType)) mimeType = "application/octet-stream";
if (mimeType.startsWith("image/") && path.startsWith("/images"))
{
IwcmFile f = new IwcmFile(Tools.getRealPath(path));
if (f.exists() && f.canRead()) {
FilePathTools.writeFileOut(f, req, res);
//Logger.println(this,"Zapisany subor: " + path);
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
return;
}
}
}
//preposlanie suboru z historie, tiket 13373, parameter pochadza z file_history.jsp
if (req.getParameter("fHistoryId")!=null && user != null && user.isAdmin())
{
int fHistoryId = Tools.getIntValue(req.getParameter("fHistoryId"), -1);
if (fHistoryId > 0)
{
boolean sendOK = FileHistoryDB.sendFileFromHistory(path, fHistoryId, res);
if (sendOK == false)
{
res.setStatus(404);
}
return;
}
}
if (path.startsWith("/templates/")) {
Ninja.includeNinja(req);
}
//forward(request, response);
//return;
}
catch (RuntimeException rex)
{
sk.iway.iwcm.Logger.error(rex);
}
catch (Exception ex)
{
if (ex.getClass().getCanonicalName().startsWith("org.spring")) throw ex;
else
{
sk.iway.iwcm.Logger.error(ex);
}
}
if (timer != null)
{
timer.diff(" Path filter - chain, path: " + path);
DBPool.getInstance().logConnections();
}
if (handleStrutsRedirect(req, res)) return;
try
{
// Pass control on to the next filter
chain.doFilter(servletRequest, servletResponse);
}
catch (NestedServletException|org.springframework.security.access.AccessDeniedException e)
{
//nastane napr. pri volani /admin/adminlog/logging ak user nema pravo na cmp_adminlog
//rest sluzby si to handluju same, toto sa tyka webview
//neda sa zachytit priamo AccessDeniedException preto chytame NestedServletException
if (e.getCause().toString().contains("AccessDeniedException"))
{
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
//ak to nie je rest posli ho aj na defaultnu 403 stranku
if (path==null || path.contains("/rest")==false) forwardSafely("/403.jsp", req, res);
}
else
{
throw e;
}
}
}
//these URL are nahdled by Servlet, so no need to forward it to Spring version
private static String[] strutsUrlServletExceptions = {
"/showdoc.do",
"/admin/offline.do",
"/admin/docdel.do",
"/preview.do",
"/admin/multiplefileupload.do",
"/formmail.do",
"/logoff.do",
"/admin/logoff.do"
};
/**
* Handle old struts *.do calls, it will be redirected to *.struts mappings which is handled by Spring MVC
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private boolean handleStrutsRedirect(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String path = PathFilter.getOrigPath(request);
String doShowdocAction = request.getParameter("doShowdocAction");
if (Tools.isNotEmpty(doShowdocAction) && ShowDoc.isDoShowdocActionAllowed(doShowdocAction)) path = doShowdocAction;
if (path==null) path = request.getRequestURI();
if (path.endsWith(".do")) {
//this is handled directly by servlet, no need to forward
if (Tools.containsOneItem(strutsUrlServletExceptions, path)==false) {
Logger.debug(PathFilter.class, "Forwarding old struts path: " + path);
request.getRequestDispatcher(Tools.replace(path, ".do", ".struts")).forward(request, response);
return true;
}
}
return false;
}
/**
* Skontroluje, ci je mozne pristupit k verejnej casti webu, nie admin casti
* @author kmarton
*
* @param request
* @return
*/
public static boolean checkWebAccess(HttpServletRequest request, String path)
{
Identity user = UsersDB.getCurrentUser(request);
//kontrola referer hlavicky (CSRF), je povinna pre POST alebo ked je prihlaseny user
String pathLC = path.toLowerCase();
if (user != null || "POST".equalsIgnoreCase(request.getMethod()) || pathLC.endsWith(".do") || pathLC.endsWith(".action"))
{
boolean isUrlAccessible = true;
boolean xsrfUrlException = DocTools.isXssStrictUrlException(path, "xsrfUrlException");
if (xsrfUrlException==false && isXsrfCheckRequired(request))
{
isUrlAccessible = checkXsrf(request);
}
//nastal CSRF utok, referer nesedi
if (isUrlAccessible==false) return false;
}
//kontrola pristupu do /components/ adresara
if ((path.startsWith("/components/") || path.startsWith("/apps/"))
&& (path.endsWith(".jsp") || path.endsWith(".ftl") || path.endsWith(".html")))
{
if (user == null || user.isAdmin()==false)
{
boolean canAccess = DocTools.isXssStrictUrlException(path, "componentsDirectCallExceptions");
if (canAccess==false)
{
//ak to zacina na /apps/ over este, ci to nie je platna URL adresa stranky
int docId = -1;
if (path.startsWith("/apps/")) docId = DocDB.getInstance().getDocIdFromURLImpl(path, DocDB.getDomain(request));
if (docId < 1)
{
Adminlog.add(Adminlog.TYPE_XSS, "Direct component call, path="+path, -1, -1);
return false;
}
}
//duplicitna kontrola, v ziadnom pripade nema zmysel pristupovat na komponenty s URL obsahujucim admin a tiez do statistiky
if (canAccess && path.contains("admin_answer.jsp")) return canAccess;
if (path.contains("admin"))
{
if (user != null && (path.contains("FCKeditor") || path.contains("/components/gallery/admin_gallery_popup.jsp") ||
path.contains("/components/helpdesk/fotogaleria/admin_upload.jsp")))
{
//specialna vynimka pre CK editor pre rozne projekty kde je user prihlaseny ale nie je admin
//+ #17331 - pridana vynimka pre upload suboru vo fotogalerii v intre
}
else
{
return false;
}
}
if (path.contains("/components/stat/") && path.contains("stat_async_ajax.jsp") == false) return false;
}
}
//kontrola pristupu podla povolenych IP adries
HttpSession session = request.getSession();
Boolean val = (Boolean) session.getAttribute(CHECK_WEB_ACCESS_SESSION_KEY);
if (val != null)
{
//Logger.println(this,"Checking to access web from session: " + val.booleanValue());
return (val.booleanValue());
}
boolean ret = Tools.checkIpAccess(request, "webEnableIPs");
session.setAttribute(CHECK_WEB_ACCESS_SESSION_KEY, Boolean.valueOf(ret));
return (ret);
}
/**
* Skontroluje, ci je mozne pristupit k verejnej casti webu na zaklade domeny<br />
*
* Castokrat web najskor bezi na domene nieco.t8.iway.sk a nasledne sa spusti na
* domenie nieco.sk, filter umoznuje zadat domeny, pre ktore bude stranka
* vracat obsah a pre ktore bude robit 404 / redirect na inu domenu.
* @author kmarton
*
* @param request
* @return
*/
private boolean checkDomain(HttpServletRequest request)
{
HttpSession session = request.getSession();
Boolean val = (Boolean) session.getAttribute(CHECK_DOMAIN_SESSION_KEY);
if (val != null)
{
//Logger.println(this,"Checking DOMAIN to access web from session: " + val.booleanValue());
return (val.booleanValue());
}
String webAllowedDomains = Constants.getString("webAllowedDomains");
boolean ret = true;
if (webAllowedDomains != null && webAllowedDomains.length() > 1)
{
ret = false;
StringTokenizer st = new StringTokenizer(webAllowedDomains, ",");
String domain;
String myDomain = Tools.getServerName(request);
Logger.println(this,"Checking: " + myDomain + " vs " + webAllowedDomains);
while (st.hasMoreTokens())
{
domain = st.nextToken();
if (myDomain.endsWith(domain))
{
ret = true;
break;
}
}
}
session.setAttribute(CHECK_DOMAIN_SESSION_KEY, Boolean.valueOf(ret));
return (ret);
}
private boolean checkAccessToAdmin(String path, HttpServletRequest request, HttpServletResponse response)
{
boolean isAdminUrlAccessible = true;
Identity user = UsersDB.getCurrentUser(request.getSession());
boolean xsrfUrlException = DocTools.isXssStrictUrlException(path, "xsrfUrlException");
if(path.startsWith("/admin") ||
(path.startsWith("/components/") && path.contains("/admin")) ||
(path.startsWith("/apps/") && path.contains("/admin"))) //pristupuje do admin casti a admin komponent/app
{
if(user == null || UsersDB.checkUserPerms(user, "admin|editableGroupsNotEmpty")==false) //A nie je prihlaseny, alebo nie je prihlaseny ako admin
{
isAdminUrlAccessible = false;
String allowAdminUrls = Constants.getString("allowAdminUrls");
//ak v starom WJ mali customizovanu premennu a nemaju tam springove prihlasenie, pridajme
if (allowAdminUrls.contains("/admin/logon.do") && allowAdminUrls.contains("/admin/logon/")==false) allowAdminUrls += ",^/admin/logon$,^/admin/logon/$,^/admin/logon/changePassword$";
String[] adminUrls = Tools.getTokens(allowAdminUrls, ",", true);
for(String url: adminUrls)
{
if(path.startsWith(url) || ("^"+path+"$").equals(url) || (path+"$").endsWith(url))
{
isAdminUrlAccessible = true;
break;
}
}
}
if(isAdminUrlAccessible && xsrfUrlException==false)
{
isAdminUrlAccessible = checkXsrf(request);
}
if (path.endsWith(".html") || path.endsWith(".jsp") || path.endsWith(".action") || path.endsWith(".do") || path.endsWith(".js") || path.endsWith("/") || path.indexOf("ajax")!=-1)
{
setUaCompatibleAdmin(path, response);
}
}
if (user != null && user.isAdmin())
{
if (xsrfUrlException==false)
{
if (isXsrfCheckRequired(request))
{
isAdminUrlAccessible = checkXsrf(request);
}
}
}
return isAdminUrlAccessible;
}
/**
* Overi, ci je potrebna XSRF kontrola (kontrola referera)
* ta sa robi pri POST alebo ked v URL su nejake parametre (okrem vynimiek definovanych v xsrfParamNameException ako docid, _logLevel, combineEnabled atd)
* @param request
* @return
*/
private static boolean isXsrfCheckRequired(HttpServletRequest request)
{
//ak uz je user prihlaseny ako admin, kontrolujme CSRF vzdy (aby sa nedal spravit utok z inej stranky mazuci napr. data)
//niektore URL musime whitelistovat, kedze mozu viest z mailu
boolean isXsrfCheckRequired = false;
if ("GET".equalsIgnoreCase(request.getMethod()))
{
Enumeration<String> paramNames = request.getParameterNames();
int failsafe = 0;
int maxFailsafe = 10;
String xsrfParamNames = Constants.getString("xsrfParamNameExceptionSystem");
if (Tools.isNotEmpty(Constants.getString("xsrfParamNameException"))) xsrfParamNames += "," + Constants.getString("xsrfParamNameException");
String[] xsrfParamNameException = Tools.getTokens(xsrfParamNames.toLowerCase(), ",", true);
while (paramNames.hasMoreElements() && failsafe++ <= maxFailsafe)
{
String name = paramNames.nextElement().toLowerCase();
//natvrdo kvoli performance
if ("docid".equals(name)) continue;
//displaytag povolime
if (name.startsWith("d-")) continue;
//over voci zoznamu povolenych parametrov
if (Tools.containsOneItem(xsrfParamNameException, name)) continue;
isXsrfCheckRequired = true;
}
//ak to ma vela parametrov tak to je rovno podozrive
if (failsafe>=maxFailsafe) isXsrfCheckRequired = true;
}
else {
//pre POST je check required
isXsrfCheckRequired = true;
}
return isXsrfCheckRequired;
}
/**
* Method checks for XSRF attack, if referrer from request header is not current server
* or from list of trusted referrers (constant xsrfReferers, see {@link Constants} ) method denies
* access to url and logs attack. for more information see Ticket 11207
* @param request request
* @return true if xsrf is not detected, else false
*/
private static boolean checkXsrf(HttpServletRequest request)
{
String trustedXsrfReferers = Constants.getString("xsrfReferers");
//ten length je tam aby v Oracle DB bolo mozne v konfiguracii nastavit znak -
if(Tools.isEmpty(trustedXsrfReferers) || trustedXsrfReferers.length()<2) return true;
String remoteReferrer = request.getHeader("referer");
if(Tools.isEmpty(remoteReferrer))
{
//vynimka pre elfinder download - /admin/elfinder-connector/?cmd=file&target=iwcm_2_L2ZpbGVzL3pfb19wcmlzcF9uYV9wb2hyZWJfcGRmLnBkZg_E_E&download=1&volumes=files
//nechcel som dat vynimku pre cely elfinder-connector, preto sa testuje parameter download
String path = PathFilter.getOrigPath(request);
if ("/admin/elfinder-connector/".equals(path) && "1".equals(request.getParameter("download")))
{
return true;
}
//do slaka, MSIE posiela empty referer ked otvara popup okno, takze zial MSIE nebude pre GET poziadavky chranene
String userAgent = request.getHeader("User-Agent");
boolean isMsie = false;
if (userAgent!=null && "GET".equalsIgnoreCase(request.getMethod()))
{
//vynimka len pre Trident/7.0 co je MSIE 11, starsi MSIE nebude podporovany (jedine ochranu uplne vypnut)
if (userAgent.contains("Trident/7.0")) isMsie = true;
}
if (isMsie==false && isXsrfCheckRequired(request))
{
Adminlog.add(Adminlog.TYPE_XSRF, "Possible XSRF attack, referer is empty", -1, -1);
return false;
}
return true;
}
String remoteReferrerServer = "";
try
{
URL remoteReferrerUrl = new URL(remoteReferrer);
remoteReferrerServer = remoteReferrerUrl.getHost();
}
catch (Exception e)
{
Logger.debug(PathFilter.class,"Failed to create URL from referrer: " + remoteReferrer);
}
for(String trustedReferrer : trustedXsrfReferers.split(","))
{
trustedReferrer = trustedReferrer.trim();
if(trustedReferrer.equalsIgnoreCase(Constants.SERVER_NAME_MACRO))
{
trustedReferrer = Tools.getServerName(request, false);
}
if (trustedReferrer.startsWith("%") && trustedReferrer.endsWith("%") && trustedReferrer.length()>4 && remoteReferrerServer.contains(trustedReferrer.substring(1, trustedReferrer.length()-1)))
{
return true;
}
if (trustedReferrer.startsWith("%") && trustedReferrer.length()>2 && remoteReferrerServer.endsWith(trustedReferrer.substring(1)))
{
return true;
}
if(remoteReferrerServer.equalsIgnoreCase(trustedReferrer))
{
return true;
}
}
Adminlog.add(Adminlog.TYPE_XSRF, "Possible XSRF attack from: " + remoteReferrer, -1, -1);
return false;
}
/**
* Skontroluje, ci je mozne pristupit k admin casti
*
* @param request
* @return
*/
public static boolean checkAdmin(HttpServletRequest request)
{
HttpSession session = request.getSession();
Boolean val = (Boolean) session.getAttribute(CHECK_ADMIN_SESSION_KEY);
if (val != null)
{
return (val.booleanValue());
}
if ("public".equals(Constants.getString("clusterMyNodeType"))) return false;
String adminEnableIPs = Constants.getString("adminEnableIPs");
boolean ret = true;
if (adminEnableIPs != null && adminEnableIPs.length() > 1)
{
ret = false;
StringTokenizer st = new StringTokenizer(adminEnableIPs, ",");
String ip;
String myIP = Tools.getRemoteIP(request);
Logger.println(PathFilter.class,"Checking: " + myIP + " vs " + adminEnableIPs);
while (st.hasMoreTokens())
{
ip = st.nextToken().trim();
if (myIP.startsWith(ip))
{
ret = true;
break;
}
}
}
session.setAttribute(CHECK_ADMIN_SESSION_KEY, Boolean.valueOf(ret));
return (ret);
}
/**
* Nacita z databazy zoznam adresarov, v ktorych su chranene subory
*
*/
public static synchronized void reloadProtectedDirs()
{
Map<String, EditForm> protectedDirs = new HashMap<>();
Connection db_conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
db_conn = DBPool.getConnection();
ps = db_conn.prepareStatement("SELECT * FROM dirprop"); //NOSONAR
rs = ps.executeQuery();
EditForm ef;
String passProtected;
while (rs.next())
{
passProtected = DB.getDbString(rs, "password_protected");
if (Tools.isEmpty(passProtected))
{
continue;
}
ef = new EditForm();
ef.setPasswordProtectedString(passProtected);
ef.setOrigDir(DB.getDbString(rs, "dir_url"));
ef.setIndexFulltext(rs.getBoolean("index_fulltext"));
ef.setLogonDocId(rs.getInt("logon_doc_id"));
protectedDirs.put(ef.getOrigDir(), ef);
}
rs.close();
ps.close();
rs = null;
ps = null;
}
catch (Exception sqlEx)
{
//ak este nie je spraveny update toto hadze exception
if (sqlEx.getMessage().indexOf("doesn't exist")!=-1)
{
sk.iway.iwcm.Logger.error(sqlEx);
}
}
finally
{
try
{
if (db_conn != null)
db_conn.close();
if (rs != null)
rs.close();
if (ps != null)
ps.close();
}
catch (Exception ex2)
{
}
}
passwordProtected = protectedDirs;
}
/**
* Skontroluje, ci zadane URL je v protected zone
* @param url
* @return EditForm ak je chranene, alebo null
*/
public static EditForm isPasswordProtected(String url, HttpServletRequest request)
{
if (request == null) return isPasswordProtected(url, null, null);
return isPasswordProtected(url, request, request.getSession());
}
/**
* Skontroluje prava k danemu URL (suboru)
* @param url - url adresa suboru z adresara /files
* @param request - ak nie je null prida sa aj statistika videni (ak statistiku nechceme zaratat nastavime len session)
* @param session - session z ktorej sa ziska identita pouzivatela
* @return
*/
public static EditForm isPasswordProtected(String url, HttpServletRequest request, HttpSession session)
{
boolean galleryCheckUserPerms = Constants.getBoolean("galleryCheckUserPerms");
if (url.startsWith("/files")==false && (url.startsWith("/images/gallery/")==false || galleryCheckUserPerms == false))
{
return(null);
}
if (session == null && request != null) session = request.getSession();
EditForm efBestMatch = null;
if(passwordProtected != null && passwordProtected.size() > 0)
{
String testPath = url;
int start = 1; //nastavit musim na 1, aby v pripade prvej podmienky islo do while cyklu
if (testPath.endsWith("/")) testPath = testPath.substring(0, testPath.length()-1);
else if(testPath.contains(".")) //ak sa jedna o subor - vytiahnem adresar
{
start = testPath.lastIndexOf("/");
if(start != -1) testPath = testPath.substring(0, testPath.lastIndexOf("/"));
}
EditForm ef = null;
int failsafe = 0;
String firstTestPath = "";
//hladam najblizsi nadradeny adresar kotry je password protected
while (start > 0 && failsafe++ < 30)
{
if(failsafe == 1) firstTestPath = testPath;
ef = passwordProtected.get(testPath);
if(ef != null)
{
efBestMatch = ef;
//pokial som nenasiel v prvom pokuse, pridam do zoznamu, nech pri dalsom volani neiterujem zbytocne + ochrana proti DOC utokom
if(failsafe > 1 && passwordProtected.size() < 2000) passwordProtected.put(firstTestPath, ef);
break;
}
start = testPath.lastIndexOf("/");
if (start > 0) testPath = testPath.substring(0, start); //substring len v pripade ak lomitko nieje na zaciatku
}
}
if (url.startsWith("/files"))
{
//pre files skus skontrolovat ci nie je zaheslovany v sekcii /files/
DocDB docDB = DocDB.getInstance();
int docId = docDB.getDocIdFromURLImpl(url+".html", null);
if (docId < 1) docId = docDB.getDocIdFromURLImpl(url+".html", DocDB.getDomain(request));
if (docId < 1) docId = docDB.getDocIdFromURLImpl(Tools.replace(url, ".", "-")+".html", null);
if (docId < 1) docId = docDB.getDocIdFromURLImpl(Tools.replace(url, ".", "-")+".html", DocDB.getDomain(request));
if (docId > 0)
{
DocDetails fileDoc = docDB.getBasicDocDetails(docId, false);
if (fileDoc != null)
{
Identity user = null;
if (session != null) user = UsersDB.getCurrentUser(session);
else
{
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
if (rb!=null && rb.getUserId()>0) user = new Identity(UsersDB.getUser(rb.getUserId()));
}
boolean canAccess = DocDB.canAccess(fileDoc, user, true);
boolean isAvailable = fileDoc.isAvailable();
if (isAvailable == false && user != null && user.isAdmin() && Constants.getBoolean("adminCheckUserGroups")==false)
{
//ak je admin ignorujeme nastavenie available atributu stranky
isAvailable = true;
}
if (!canAccess || !isAvailable)
{
efBestMatch = new EditForm();
//to cislo je bulharska konstanta len aby nam potom nezbehlo ef.isAccessibleFor, pretoze to neriesi podadresare dokumentu
efBestMatch.setPasswordProtectedString("999888777");
}
else
{
try
{
if (request != null)
{
StatDB.add(request.getSession(), request, null, docId);
}
}
catch (Exception e)
{
sk.iway.iwcm.Logger.error(e);
}
}
}
}
}
return(efBestMatch);
}
/**
* Vykona redirect (ak treba) na zobrazenie logon stranky / zamietnutia pristupu k suboru (/files/*), vrati true, ak bol redirect vykonany
* @param ef
* @param user
* @param originalPath
* @param req
* @param res
* @return true ak je redirect vykonany, inak false
* @throws IOException
* @throws ServletException
*/
public static boolean doFileForbiddenRedirect(EditForm ef, Identity user, String originalPath, HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException
{
boolean isAccesible = false;
if (user != null && ef!=null)
{
//otestuj, ci je user v skupine pre tento adresar
int i;
int size = ef.getPasswordProtected().length;
for (i=0; i<size; i++)
{
if (user.isInUserGroup(ef.getPasswordProtected()[i]))
{
isAccesible = true;
break;
}
}
}
if (isAccesible) return false;
String pathQS = originalPath;
if (Tools.isNotEmpty(req.getQueryString())) pathQS = originalPath + "?" + req.getQueryString();
Logger.debug(PathFilter.class, "NOT ACCESSIBLE: path="+pathQS+" user="+user);
if (user != null)
{
//user nema pristup, daj mu forbidden
int fileAccessDeniedDocId = Constants.getInt("fileAccessDeniedDocId");
Logger.debug(PathFilter.class, "fileAccessDeniedDocId="+fileAccessDeniedDocId+" ntlm="+AuthenticationFilter.getForbiddenURL());
if (fileAccessDeniedDocId > 0)
{
res.setHeader("Pragma","No-Cache");
res.setDateHeader("Expires",0);
res.setHeader("Cache-Control","no-Cache");
req.setAttribute("logonFormSubmitURL", originalPath);
req.getRequestDispatcher("/showdoc.do?docid="+fileAccessDeniedDocId+"&origUrl="+Tools.URLEncode(pathQS)).forward(req, res);
}
else if (Tools.isNotEmpty(AuthenticationFilter.getForbiddenURL()))
{
res.sendRedirect(Tools.addParameterToUrlNoAmp(AuthenticationFilter.getForbiddenURL(), "origUrl", pathQS));
}
else
{
res.setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
else
{
//forwardni sa na logon stranku
req.getSession().setAttribute("afterLogonRedirect", pathQS);
res.setHeader("Pragma","No-Cache");
res.setDateHeader("Expires",0);
res.setHeader("Cache-Control","no-Cache");
if (ef != null && ef.getLogonDocId()>0)
{
//res.sendRedirect("/showdoc.do?docid="+ef.getLogonDocId());
//request.setAttribute("docDetailsOriginal", doc);
//pre subor sa musime submitnut priamo na usrlogon.do aby sa najskor spravilo prihlasenie az potom kontrola prav na subor
req.setAttribute("logonFormSubmitURL", "/usrlogon.do");
req.getRequestDispatcher("/showdoc.do?docid="+ef.getLogonDocId()+"&dontUpdateLastDocId=true").forward(req, res);
}
else
{
req.getRequestDispatcher("/components/user/logon.jsp?permsDenied=true").forward(req, res);
}
}
return true;
}
/**
* Vrati cestu k suboru na disku z daneho URL, berie do uvahy aj custom path
* @param url - url adresa suboru, napr. /css/page.css
* @return - vrati cestu na disku, napr. /var/webapps/webjet/css/page.css
*/
public static String getRealPath(String url)
{
if (customPath != null)
{
//skontroluj, ci pozadovany subor nie je custom
File f = new File(customPath + File.separatorChar + Constants.getInstallName() + (url.startsWith("/")?"":File.separatorChar) + url.replace('/', File.separatorChar));
//Logger.println(this,"Checking CUSTOM: "+f.getAbsolutePath());
if (f.exists())
{
return(f.getAbsolutePath());
}
}
return(Tools.getRealPath(url));
}
public static String getOrigPath(HttpServletRequest request)
{
return((String)request.getAttribute("path_filter_orig_path"));
}
/**
* Vrati adresu povodnej stranky, v pripade DOCID liniek vratane parametra docid
* @param request
* @return
*/
public static String getOrigPathDocId(HttpServletRequest request)
{
if (Constants.getInt("linkType")==Constants.LINK_TYPE_DOCID && request.getParameter("docid")!=null)
{
return "/showdoc.do?docid="+Tools.getDocId(request);
}
String origPath = getOrigPath(request);
if ("/showdoc.do".equals(origPath)) origPath = origPath + "?docid=" + Tools.getDocId(request);
return origPath;
}
/**
* Vrati adresu povodnej stranky, v pripade DOCID liniek vratane docid s pridanym
* parametrom pre uload suboru pre stripes (aby to Stripes spracoval)
* @param request
* @return
*/
public static String getOrigPathUpload(HttpServletRequest request)
{
if (Constants.getInt("linkType")==Constants.LINK_TYPE_DOCID && request.getParameter("docid")!=null)
{
return "/showdoc.do?docid="+Tools.getDocId(request) +"&__sfu=1";
}
return getOrigPath(request)+"?__sfu=1";
}
public static boolean bypassPath(String path, ServletRequest servletRequest)
{
//aby nam lokalne fungoval customPath
if (Tools.isNotEmpty(PathFilter.getCustomPath()) && "iwcm.interway.sk".equals(servletRequest.getServerName())) return false;
if (bypassPath == null)
{
synchronized(PathFilter.class) //NOSONAR
{
if (bypassPath == null)
{
String[] tokens = Tools.getTokens(Constants.getString("pathFilterBypassPath"), ",", true);
bypassPath = tokens == null ? new String[0] : tokens;
}
}
}
if (bypassPath.length > 0)
{
for (int i=0; i<bypassPath.length; i++)
{
if (path.startsWith(bypassPath[i])) return(true);
}
}
return(false);
}
/**
* Nastavi cache hlavicky podla konf. premennej cacheStaticContentSeconds a cacheStaticContentSuffixes
* @param path
* @param user
* @param request
* @param response
* @return
*/
public static boolean setStaticContentHeaders(String path, Identity user, HttpServletRequest request, HttpServletResponse response)
{
if (path.startsWith("/cache/")==false && request.getParameter("v")!=null)
{
//vygeneruj odkaz bez v parametra, negeneruje pre fiktivne /cache/nieco.css linky
String canonicalLink = Tools.getBaseHref(request) + path;
response.setHeader("Link", "<"+canonicalLink+">; rel=\"canonical\"");
}
//vypnutie cachovania pre obrazky z imageeditora
if (path.contains("/_tmp_"))
{
response.setDateHeader("Expires",0);
response.setDateHeader("Last-Modified", Tools.getNow());
response.setHeader("Cache-Control","no-store, no-cache, must-revalidate, max-age=0");
//response.setHeader("Cache-Control","post-check=0, pre-check=0");
response.setHeader("Pragma","No-Cache");
response.setHeader("Etag", "");
return false;
}
if (cacheStaticContentSeconds < 0)
{
cacheStaticContentSeconds = Constants.getInt("cacheStaticContentSeconds");
}
if (cacheStaticContentSuffixes == null)
{
synchronized(PathFilter.class) //NOSONAR
{
if (cacheStaticContentSuffixes == null)
{
String[] tokens = Tools.getTokens(Constants.getString("cacheStaticContentSuffixes"), ",", true);
cacheStaticContentSuffixes = tokens == null ? new String[0] : tokens;
}
}
}
//prefixom /cache mame oznacene veci, co sa musia cachovat kvoli rychlosti admin casti (/admin/scripts/common.jsp)
if (path.startsWith("/cache/")==false)
{
if (cacheStaticContentSeconds<1 || cacheStaticContentSuffixes==null || cacheStaticContentSuffixes.length<1) return false;
//administratorom cache nenastavujem (okrem admin casti, tam sa to casto nemeni)
if (user!=null && user.isAdmin() && path.startsWith("/admin")==false && path.startsWith("/components")==false && Constants.getBoolean("cacheStaticContentForAdmin")==false) return false;
//pre IP pre ktore neevidujeme statistiku nenastavujem (pravdepodobne IWAY + admini)
if (Constants.getBoolean("cacheStaticContentForAdmin")==false && BrowserDetector.isStatIpAllowedFast(request)==false) return false;
}
//String pathLC = path.toLowerCase();
//v parametri v sa prenasa verzia suboru, v tom pripade cachujeme
//uz cachujem aj admin cast if (pathLC.startsWith("/admin/") && (request.getParameter("v")==null && request.getParameter("t")==null)) return false;
int myCacheStaticContentSeconds = cacheStaticContentSeconds;
if (myCacheStaticContentSeconds < 1 && path.startsWith("/cache/")) myCacheStaticContentSeconds = 300;
//ak mame parameter v tak natvrdo nastavime cas na 7 dni
if (request.getParameter("v")!=null) myCacheStaticContentSeconds = 60 * 60 * 24 * 7;
if (path.contains("ckeditor")) myCacheStaticContentSeconds = 60 * 60 * 24 * 7;
if (path.contains("assets")) myCacheStaticContentSeconds = 60 * 60 * 24 * 7;
if (path.contains("_common")) myCacheStaticContentSeconds = 60 * 60 * 24 * 7;
if (path.contains("/admin/images/")) myCacheStaticContentSeconds = 60 * 60 * 24 * 7;
if (path.contains("/admin/v9/dist/") && myCacheStaticContentSeconds<301) myCacheStaticContentSeconds = 60 * 30;
if (myCacheStaticContentSeconds < cacheStaticContentSeconds) myCacheStaticContentSeconds = cacheStaticContentSeconds;
for (int i=0; i<cacheStaticContentSuffixes.length; i++)
{
if (path.endsWith(cacheStaticContentSuffixes[i]))
{
setCacheHeaders(myCacheStaticContentSeconds, response);
return true;
}
}
//cachovanie json pre dashboard
if (path.contains("/admin/v9/json/")) {
setCacheHeaders(60 * 60 * 24, response);
}
return false;
}
/**
* Nastavi HTTP hlavicku Content-Disposition na hdonotu attachment;filename=abc pre subory v adresaroch /files a /images
* ktore maju priponu definovanu v konf. premennej forceDownloadSuffixes
*
* Umozni to vyvolat download dialog napr. pre pdf subory namiesto ich zobrazenia v prehliadaci
*
* @param path
* @param request
* @param response
*/
public static void setDownloadHeaders(String path, HttpServletRequest request, HttpServletResponse response)
{
if (path.endsWith("/")) return;
if (path.startsWith("/images") || path.startsWith("/files"))
{
try
{
int lomka = path.lastIndexOf("/");
int bodka = path.indexOf(".", lomka);
if (lomka > 0 && bodka > lomka)
{
String fileName = path.substring(lomka + 1);
if (isForceDownload(fileName))
{
response.setHeader("Content-Disposition", "attachment;filename="+fileName);
}
}
}
catch (Exception ex)
{
sk.iway.iwcm.Logger.error(ex);
}
}
}
public static boolean isForceDownload(String fileName) {
String forceDownloadSuffixes = Constants.getString("forceDownloadSuffixes");
String ext = FileTools.getFileExtension(fileName);
return (Tools.isNotEmpty(forceDownloadSuffixes) && forceDownloadSuffixes.contains(ext));
}
/**
* Nastavi cache hlavicky na pozadovanu hodnotu v sekundach
* @param myCacheStaticContentSeconds
* @param response
*/
public static void setCacheHeaders(int myCacheStaticContentSeconds, HttpServletResponse response)
{
response.setHeader("Cache-Control", "max-age="+myCacheStaticContentSeconds);
if (response.containsHeader("Pragma")) response.setHeader("Pragma","");
if (response.containsHeader("Expires")) response.setDateHeader("Expires", Tools.getNow()+myCacheStaticContentSeconds*1000);
}
/**
* Cache pre staticke subory, cachuju sa len subory pre ktore sa nastavuje setStaticContentHeaders
* @param url
* @return
*/
public static boolean writeAndCacheFile(String url, HttpServletResponse response)
{
//ak je cache vypnuta, neriesime
if (FileCache.useFileCache() == false) return false;
//pre DB storage tu cache neriesime, to sa riesi priamo v IwcmFsFilter
if (IwcmFsDB.useDBStorage()) return false;
String mimeType = Constants.getServletContext().getMimeType(url.toLowerCase());
if (Tools.isEmpty(mimeType)) mimeType = "application/octet-stream";
response.setContentType(mimeType);
byte[] data = FileCache.getObject(url);
if (data != null)
{
response.setContentLength(data.length);
try
{
OutputStream out=response.getOutputStream();
out.write(data);
out.close();
return true;
}
catch (Exception ex)
{
sk.iway.iwcm.Logger.error(ex);
}
}
else
{
IwcmFile f = new IwcmFile(Tools.getRealPath(url));
if (f.length() > FileCache.getMaxFileSize()) return false;
response.setContentLength((int)f.length());
//nacitaj data do pola
data = new byte[(int)f.length()];
boolean dataCopied = false;
IwcmInputStream in = null;
try
{
OutputStream out=response.getOutputStream();
in = new IwcmInputStream(f);
byte[] buffer = new byte[64000];
int bytesRead = 0;
int bytesCopied = 0;
while ((bytesRead = in.read(buffer, 0, 64000)) != -1)
{
//Logger.debug(IwcmFsDB.class, "writing "+bytesRead);
out.write(buffer, 0, bytesRead);
System.arraycopy(buffer, 0, data, bytesCopied, bytesRead);
bytesCopied+=bytesRead;
}
out.flush();
out.close();
in.close();
dataCopied = true;
}
catch (Exception e)
{
sk.iway.iwcm.Logger.error(e);
}
finally
{
if (in != null) try { in.close(); } catch (Exception e) {}
}
if (dataCopied)
{
FileCache.setObject(url, data);
return true;
}
}
return false;
}
/**
* Nastavenie hlavicky X-Robots-Tag, viz https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
* @param url
* @param response
*/
public static void setXRobotsTagValue(String url, HttpServletResponse response)
{
String xRobotsTagUrls = Constants.getString("xRobotsTagUrls");
if (Tools.isEmpty(xRobotsTagUrls)) return;
if (url.charAt(0)=='/') url = url.toLowerCase(); //aby sa nam NOT_SEARCHABLE_PAGE nezmenilo na male pismena
String[] paths = Tools.getTokens(xRobotsTagUrls, ",", true);
for (String path : paths)
{
if (ResponseHeaderService.isPathCorrect(path, url))
{
String xRobotsTagValue = Constants.getStringExecuteMacro("xRobotsTagValue");
if (Tools.isNotEmpty(xRobotsTagValue))
{
response.setHeader("X-Robots-Tag", xRobotsTagValue);
return;
}
}
}
}
public static void setUaCompatibleAdmin(String path, HttpServletResponse response)
{
String xUaCompatibleAdminValue = Constants.getString("xUaCompatibleAdminValue");
if (Tools.isEmpty(xUaCompatibleAdminValue)) return;
response.setHeader("X-UA-Compatible", xUaCompatibleAdminValue);
}
/**
* Nastavi hlavicku X-Frame-Options podla konfiguracnej premennej xFrameOptions
* @param response
*/
private static void setXFrameOptions(HttpServletResponse response)
{
String xFrameOptions = Constants.getString("xFrameOptions");
if (Tools.isEmpty(xFrameOptions)) return;
response.setHeader("X-Frame-Options", xFrameOptions);
}
private static void setXXssProtection(HttpServletResponse response)
{
String xXssProtection = Constants.getString("xXssProtection");
if (Tools.isEmpty(xXssProtection)) return;
response.setHeader("X-XSS-Protection", xXssProtection);
}
/**
* Nastavi hlavicku Feature-Policy podla konfiguracnej premennej featurePolicyHeader
* @param response
*/
public static void setFeaturePolicy(HttpServletResponse response)
{
String featurePolicy = Constants.getString("featurePolicyHeader");
if (Tools.isEmpty(featurePolicy)) return;
response.setHeader("Feature-Policy", featurePolicy);
response.setHeader("Permissions-Policy", featurePolicy);
}
/**
* Nastavenie hlavicky Access-Control-Allow-Origin
* @param url
* @param response
*/
public static void setAccessControlAllowOrigin(String url, HttpServletResponse response)
{
String accessControlAllowOriginUrls = Constants.getString("accessControlAllowOriginUrls");
if (Tools.isEmpty(accessControlAllowOriginUrls)) return;
String[] paths = Tools.getTokens(accessControlAllowOriginUrls, ",", true);
String accessControlAllowOriginValue = Constants.getStringExecuteMacro("accessControlAllowOriginValue");
for (String path : paths)
{
if (ResponseHeaderService.isPathCorrect(path, url))
{
if (Tools.isNotEmpty(accessControlAllowOriginValue))
{
String accessControlAllowedOrigins = Constants.getString("accessControlAllowedOrigins");
boolean canAccess = false;
if (Tools.isEmpty(accessControlAllowedOrigins))
{
canAccess = true;
}
else
{
accessControlAllowedOrigins = Tools.replace(accessControlAllowedOrigins, "\n", ",");
accessControlAllowedOrigins = Tools.replace(accessControlAllowedOrigins, "\r", ",");
RequestBean rb = SetCharacterEncodingFilter.getCurrentRequestBean();
if (rb != null) {
String origin = rb.getHeaderOrigin();
if (Tools.isNotEmpty(origin))
{
if ((","+accessControlAllowedOrigins+",").contains(","+origin+",")) canAccess = true;
}
}
}
if (canAccess)
{
response.setHeader("Access-Control-Allow-Origin", accessControlAllowOriginValue);
setHeader(response, "Access-Control-Allow-Headers", "accessControlAllowHeaders");
setHeader(response, "Access-Control-Allow-Methods", "accessControlAllowMethods");
setHeader(response, "Access-Control-Max-Age", "accessControlMaxAge");
return;
}
}
}
}
}
/**
* Nastavi HTTP hlavicku podla nazvu konfiguracnej premennej
* @param response
* @param headerName - meno HTTP hlavicky
* @param constantName - meno konfiguracnej premennej
*/
public static void setHeader(HttpServletResponse response, String headerName, String constantName)
{
String value = Constants.getStringExecuteMacro(constantName);
if (Tools.isEmpty(value)) return;
if (" ".equals(value)) value = " ";
//Logger.debug(SetCharacterEncodingFilter.class, "Setting header "+headerName+":"+value);
response.setHeader(headerName, value);
}
/**
* Nastavi hlavicky pre konkretne volania podla konfiguracnej premennej responseHeaders
* @param response
*/
private static void setResponseHeaders(String path, HttpServletRequest request, HttpServletResponse response) {
if (path.startsWith("/files") || path.startsWith("/images") || path.startsWith("/shared")) {
String lngCode = Constants.getString("defaultLanguage");
//set last known language for files and images folder
if (path.contains("/en/")) lngCode = "en";
else if (path.contains("/de/")) lngCode = "de";
else if (path.contains("/cz/")) lngCode = "cz";
else if (path.contains("/sk/")) lngCode = "sk";
else lngCode = PageLng.getUserLng(request);
String isoCode = PageLng.getUserLngIso(lngCode);
ResponseHeaderService.setContentLanguageHeader(isoCode, true, request, response);
}
// parse and cache
if(responseHeaders == null) {
synchronized (PathFilter.class) {
String[] headers = Tools.getTokens(Constants.getString("responseHeaders"), "\n");
if(headers.length > 0) {
responseHeaders = new ArrayList<>();
for(int i = 0; i < headers.length; i++) {
responseHeaders.add(new ResponseHeaderBean(headers[i]));
}
}
}
}
// set headers
if(responseHeaders != null) {
for(ResponseHeaderBean header : responseHeaders) {
if(path.startsWith(header.getUrl())) {
response.setHeader(header.getName(), Constants.executeMacro(header.getValue()));
}
}
}
ResponseHeaderService.setResponseHeaders(path, request, response);
}
/**
* Ak existuje _mobile.jsp verzia zadaneho JSP vykona nan interny forward a vrati true pre ukoncenie povodneho JSP, nieco ako:
* if (PathFilter.forwardToMobileOrTablet("/components/magzilla/new_bug_popup.jsp", pageContext)) return;
* @param jspFileName
* @param context
* @return
*/
public static boolean forwardToMobileOrTablet(String jspFileName, PageContext context)
{
if (BrowserDetector.isSmartphoneOrTablet((HttpServletRequest)context.getRequest())==false) return false;
String mobileJsp = Tools.replace(jspFileName, ".jsp", "_mobile.jsp");
if (FileTools.isFile(mobileJsp)==false) return false;
try
{
context.forward(mobileJsp);
return true;
}
catch (Exception e)
{
sk.iway.iwcm.Logger.error(e);
}
return false;
}
/**
* Pouziva sa v spojeni s nginx cache proxy serverom, nastavuje cookie s nazvom nc ktora nasledne v
* dalsich http requestoch od klienta zamedzi posielaniu cache vysledkov (ak je nastavena na hodnotu 1)
* @param request
* @param response
*/
public static void setNginxProxyMode(HttpServletRequest request, HttpServletResponse response)
{
try
{
if (Constants.getBoolean("nginxProxyMode")==false) return;
String actualCookieValue = Tools.getCookieValue(request.getCookies(), "nc", null);
Cookie c = new Cookie("nc", "1");
c.setPath("/");
//ak potrebujeme nastavit nocache cookie
if (isNoCacheCookieRequired(request))
{
//ak uz je nastavena na 1 tak ju nemusime nastavovat
if ("1".equals(actualCookieValue)==false) {
//session cookie
c.setMaxAge(-1);
//toto nesmie ist cez Tools.addCookie pretoze sa ani v pripade EU smernice nemoze vypnut
response.addCookie(c);
}
}
else
{
if ("1".equals(actualCookieValue)) {
//cookie nam prisla v http requeste ale uz ju nemam setovat, takze ju dam zmazat
c.setMaxAge(0);
//toto nesmie ist cez Tools.addCookie pretoze sa ani v pripade EU smernice nemoze vypnut
response.addCookie(c);
}
}
}
catch (Exception e)
{
sk.iway.iwcm.Logger.error(e);
}
}
/**
* Overi, ci je mozne pouzit nginx proxy rezim (konstanta nginxProxyMode), ak je povoleny, overuje este:
* prihlaseneho pouzivatela (rezim nedostupny)
* prepnutie verzie cez forceBrowserDetector (ak je ina verzia ako pc nedostupne)
* @param request
* @return
*/
public static boolean isNoCacheCookieRequired(HttpServletRequest request)
{
if (request.getSession()!=null)
{
if (request.getSession().getAttribute(Constants.USER_KEY)!=null) return true;
else if (request.getParameter("forceBrowserDetector")!=null && "pc".equals(request.getParameter("forceBrowserDetector"))==false) return true; //NOSONAR
else if (request.getSession().getAttribute("BrowserDetector.forceBrowserDetector")!=null) return true; //NOSONAR
}
return false;
}
/**
* Vrati URL adresu pre httpS presmerovanie
* @param request
* @return
*/
public static String getHttpsRedirectUrl(HttpServletRequest request)
{
String path = PathFilter.getOrigPath(request);
String qs = request.getQueryString();
StringBuilder url = new StringBuilder("https://").append(Tools.getServerName(request)).append(path);
if (Tools.isNotEmpty(qs)) url.append('?').append(qs);
return Tools.sanitizeHttpHeaderParam(url.toString());
}
/**
* Otestuje, ci je povolene showdoc volanie pre dane docId
* @param docId - id dokumentu
* @param constantName - meno konstanty
* @return
*/
private static boolean isShowDocAllowDocId(int docId, String constantName)
{
String showDocAllowDocIds = Constants.getString(constantName);
if (Tools.isNotEmpty(showDocAllowDocIds))
{
StringTokenizer st = new StringTokenizer(showDocAllowDocIds, ",+;");
while (st.hasMoreTokens())
{
int token = Tools.getIntValue(st.nextToken().trim(), -1);
if(token == -1) continue; //preskocim
if(docId == token)
{
return true;
}
}
}
return false;
}
public static void resetResponseHeaders() {
responseHeaders = null;
}
public static void resetCacheStaticContentSeconds()
{
cacheStaticContentSeconds = -1;
cacheStaticContentSuffixes = null;
}
//pre WebJET 9 kontrolujeme pri REST volaniach CSRF token
private boolean checkCSRFToken(String path, HttpServletRequest request) {
//check URL against custom CSRF required URLs #57521
boolean isCsrfRequired = DocTools.isUrlAllowed(path, "csrfRequiredUrls", false);
if (isCsrfRequired) {
String token = request.getParameter(CSRF.getParameterName());
if (Tools.isEmpty(token)) token = request.getHeader("x-csrf-token");
if (Tools.isNotEmpty(token) && CSRF.verifyTokenAjax(request.getSession(), token))
{
return true;
}
return false;
}
if (path.startsWith("/admin/rest/")==false || path.startsWith("/admin/rest/document/") || path.startsWith("/admin/rest/datatables/") ) {
//taketo URL nekontrolujeme
return true;
}
//ak path obsahuje vyraz html tak token nie je potrebny
if (path.contains("/html") || path.contains("html/")) return true;
//pouziva sa pri prihlaseni tokenom, vtedy CSRF nie je posielane
if (request.getAttribute("csrfDisabled")!=null) return true;
String header = request.getHeader("X-CSRF-Token");
if (Tools.isEmpty(header)) {
return false;
}
return CSRF.verifyTokenAjax(request.getSession(), header);
}
private static void setCustomPath(String path) {
PathFilter.customPath = path;
}
/**
* Safely forward request dispatcher, need to use this if next statement is return
* eg. after checkAdmin you must return from PathFilter even when /404.jsp has compilation errors
* @param request
* @param response
* @param path
*/
private static void forwardSafely(String path, HttpServletRequest request, HttpServletResponse response){
try {
request.getRequestDispatcher(path).forward(request, response);
} catch (Exception ex) {
Logger.error(PathFilter.class, ex);
}
}
}