/* * Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.agiletec.aps.system.services.controller.control; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.agiletec.aps.system.RequestContext; import com.agiletec.aps.system.SystemConstants; import com.agiletec.aps.system.services.baseconfig.ConfigInterface; import com.agiletec.aps.system.services.controller.ControllerManager; import com.agiletec.aps.system.services.lang.ILangManager; import com.agiletec.aps.system.services.lang.Lang; import com.agiletec.aps.system.services.page.IPage; import com.agiletec.aps.system.services.page.IPageManager; import com.agiletec.aps.system.services.page.PageUtils; /** * Implementazione del un sottoservizio di controllo che * verifica la validità della richiesta del client. * Viene verificata la correttezza formale della richiesta tramite la * corrispondenza con una maschera. La richiesta deve essere nella forma:<br> * <code>/lingua/pagina.wp</code> oppure <code>/lingua/path_pagina/</code><br> * dove lingua è un codice lingua configurato, pagina una pagina del portale e * path_pagina il path (stile breadcrumbs) della pagina. * Se la richiesta è valida, l'oggetto lingua e l'oggetto pagina * corrispondenti alla richiesta sono inseriti nel contesto di richiesta * sotto forma di extra parametri, con i nomi "currentLang" e "currentPage", * ed il metodo service restituisce Controller.CONTINUE. * Se la richiesta non è valida, viene restituito lo stato di errore. * @author M.Diana - E.Santoboni */ public class RequestValidator extends AbstractControlService { private static final Logger _logger = LoggerFactory.getLogger(RequestValidator.class); @Override public void afterPropertiesSet() throws Exception { _logger.debug("{} ready", this.getClass().getName()); } /** * Esecuzione. Le operazioni sono descritte nella documentazione della classe. * @param reqCtx Il contesto di richiesta * @param status Lo stato di uscita del servizio precedente * @return Lo stato di uscita */ @Override public int service(RequestContext reqCtx, int status) { _logger.debug("{} invoked", this.getClass().getName()); int retStatus = ControllerManager.INVALID_STATUS; // Se si è verificato un errore in un altro sottoservizio, termina subito if (status == ControllerManager.ERROR) { return status; } try { // non devono essere rilanciate eccezioni boolean ok = this.isRightPath(reqCtx); if (ok) { if (null == reqCtx.getExtraParam(SystemConstants.EXTRAPAR_CURRENT_PAGE)) { retStatus = this.redirect(this.getNotFoundPageCode(), reqCtx); } else if (null == reqCtx.getExtraParam(SystemConstants.EXTRAPAR_CURRENT_LANG)) { retStatus = this.redirect(this.getErrorPageCode(), reqCtx); } else { retStatus = ControllerManager.CONTINUE; } } else { retStatus = this.redirect(this.getErrorPageCode(), reqCtx); } } catch (Throwable t) { retStatus = ControllerManager.SYS_ERROR; reqCtx.setHTTPError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); _logger.error("Error while validating the client request", t); } return retStatus; } private boolean isRightPath(RequestContext reqCtx) { boolean ok = false; String resourcePath; Matcher matcher; Lang lang = null; IPage page = null; if (this.getResourcePath(reqCtx).equals("/pages")) { resourcePath = getFullResourcePath(reqCtx); matcher = this._patternFullPath.matcher(resourcePath); if (matcher.lookingAt()) { ok = true; String sect1 = matcher.group(1); lang = getLangManager().getLang(sect1); page = this.getPage(matcher); } } else { resourcePath = getResourcePath(reqCtx); matcher = this._pattern.matcher(resourcePath); if (matcher.lookingAt()) { ok = true; String sect1 = matcher.group(1); String sect2 = matcher.group(2); lang = getLangManager().getLang(sect1); page = this.getPageManager().getPage(sect2); } else { //to preserve url with ".wp" suffix matcher = this._oldPattern.matcher(resourcePath); if (matcher.lookingAt()) { ok = true; String sect1 = matcher.group(1); String sect2 = matcher.group(2); lang = getLangManager().getLang(sect1); page = this.getPageManager().getPage(sect2); } } } if (!ok) return false; reqCtx.addExtraParam(SystemConstants.EXTRAPAR_CURRENT_LANG, lang); reqCtx.addExtraParam(SystemConstants.EXTRAPAR_CURRENT_PAGE, page); return true; } /** * Qualora si usasse il mapping /pages/* * restituisce un'oggetto IPage solo nel caso * in cui il path completo della pagina risulti corretto. * Qualora il path sia di lunghezza pari a zero * verrà restituita l'homepage. * @param Matcher il matcher valorizzato come segue<br> * matcher.group(1) -> lang_code<br> * matcher.group(2) -> /paginaX/paginaY<br> * matcher.group(3) -> /paginaY<br> * @return un oggetto Page oppure null */ private IPage getPage(Matcher matcher) { IPage page = null; String rootCode = this.getPageManager().getRoot().getCode(); String path = matcher.group(2); //Se il path è di tipo /it o /it/ o /it/homepage if(path.trim().length() == 0 || path.substring(1).equals(rootCode) ){ return this.getPageManager().getRoot(); } String pageCode = matcher.group(3).substring(1); IPage tempPage = this.getPageManager().getPage(pageCode); if (null != tempPage) { //la pagina esiste ed è di livello 1 //if(tempPage.getParentCode().equals(rootCode)) return tempPage; //la pagina è di livello superiore al primo e il path è corretto String fullPath = matcher.group(2).substring(1).trim(); String createdlFullPath = PageUtils.getFullPath(tempPage, "/").toString(); if (null != tempPage && createdlFullPath.equals(fullPath) ){ page = tempPage; } } return page; } /** * Recupera il ServletPath richiesto dal client. * @param reqCtx Il contesto di richiesta * @return Il ServletPath */ protected String getResourcePath(RequestContext reqCtx) { return reqCtx.getRequest().getServletPath(); } protected String getFullResourcePath(RequestContext reqCtx) { return this.getResourcePath(reqCtx) + reqCtx.getRequest().getPathInfo(); } protected String getErrorPageCode() { return this.getConfigManager().getParam(SystemConstants.CONFIG_PARAM_ERROR_PAGE_CODE); } protected String getNotFoundPageCode() { return this.getConfigManager().getParam(SystemConstants.CONFIG_PARAM_NOT_FOUND_PAGE_CODE); } protected ILangManager getLangManager() { return _langManager; } public void setLangManager(ILangManager langManager) { this._langManager = langManager; } protected IPageManager getPageManager() { return _pageManager; } public void setPageManager(IPageManager pageManager) { this._pageManager = pageManager; } protected ConfigInterface getConfigManager() { return configManager; } public void setConfigManager(ConfigInterface configService) { this.configManager = configService; } private ILangManager _langManager; private IPageManager _pageManager; private ConfigInterface configManager; @Deprecated protected Pattern _oldPattern = Pattern.compile("^/(\\w+)/(\\w+)\\Q.wp\\E"); protected Pattern _pattern = Pattern.compile("^/(\\w+)/(\\w+)\\Q.page\\E"); protected Pattern _patternFullPath = Pattern.compile("^/pages/(\\w+)((/\\w+)*)"); }