/**
* Copyright (c) 2000-2017 Liferay, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.liferay.faces.util.application.internal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.faces.FactoryFinder;
import javax.faces.application.ViewHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewDeclarationLanguage;
import javax.faces.view.ViewDeclarationLanguageFactory;
import com.liferay.faces.util.application.ResourceValidator;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;
/**
* @author Neil Griffin
*/
public class ResourceValidatorImpl implements ResourceValidator, Serializable {
// serialVersionUID
private static final long serialVersionUID = 1439627171348715228L;
// Logger
private static final Logger logger = LoggerFactory.getLogger(ResourceValidatorImpl.class);
// Private Constants
private static final Pattern BANNED_PATHS_PATTERN = Pattern.compile(".*/(?:META-INF|WEB-INF)/.*",
Pattern.CASE_INSENSITIVE);
private static final String[] BANNED_SEQUENCES = new String[] {
"//", "\\\\", "/\\", "\\/", "..", "./", ".\\", "%"
};
protected static final String DEFAULT_FACELETS_SUFFIX = ViewHandler.DEFAULT_FACELETS_SUFFIX;
protected static final String FACELETS_SUFFIX_PARAM_NAME = ViewHandler.FACELETS_SUFFIX_PARAM_NAME;
protected static final String[] VIEW_MAPPINGS_PARAM_NAMES = new String[] {
ViewHandler.FACELETS_VIEW_MAPPINGS_PARAM_NAME, "facelets.VIEW_MAPPINGS"
};
// Final Data Members
private final List<Pattern> excludeResourcePatterns;
private final List<Pattern> excludeLibraryPatterns;
/**
* @param excludeResourcePatterns a {@link java.io.Serializable} {@link ArrayList} of excluded resource patterns.
* @param excludeLibraryPatterns a {@link java.io.Serializable} {@link ArrayList} of excluded library patterns.
*/
public ResourceValidatorImpl(ArrayList<Pattern> excludeResourcePatterns,
ArrayList<Pattern> excludeLibraryPatterns) {
if (excludeResourcePatterns != null) {
this.excludeResourcePatterns = Collections.unmodifiableList(excludeResourcePatterns);
}
else {
this.excludeResourcePatterns = null;
}
if (excludeLibraryPatterns != null) {
this.excludeLibraryPatterns = Collections.unmodifiableList(excludeLibraryPatterns);
}
else {
this.excludeLibraryPatterns = null;
}
}
@Override
public boolean containsBannedPath(String resourceId) {
Matcher matcher = BANNED_PATHS_PATTERN.matcher(resourceId);
boolean matches = matcher.matches();
if (matches) {
logger.trace("MATCHED BANNED PATH resourceId=[{0}] matcher=[{1}]", resourceId, matcher);
}
return matches;
}
@Override
public boolean isBannedSequence(String resourceId) {
boolean bannedSequence = false;
if (resourceId != null) {
for (String sequence : BANNED_SEQUENCES) {
if (resourceId.contains(sequence)) {
logger.trace("MATCHED BANNED SEQUENCE resourceId=[{0}] sequence=[{1}]", resourceId, sequence);
bannedSequence = true;
break;
}
}
}
return bannedSequence;
}
@Override
public boolean isFaceletDocument(FacesContext facesContext, String resourceId) {
boolean faceletDocument = false;
List<String> faceletExtensions = new ArrayList<String>();
List<String> faceletPathMappings = new ArrayList<String>();
faceletExtensions.add(DEFAULT_FACELETS_SUFFIX);
ExternalContext externalContext = facesContext.getExternalContext();
String configuredExtension = externalContext.getInitParameter(FACELETS_SUFFIX_PARAM_NAME);
if ((configuredExtension != null) && !faceletExtensions.contains(configuredExtension)) {
faceletExtensions.add(configuredExtension);
}
List<String> viewMappings = new ArrayList<String>();
for (String viewMappingsParamName : VIEW_MAPPINGS_PARAM_NAMES) {
String configuredMappings = externalContext.getInitParameter(viewMappingsParamName);
if (configuredMappings != null) {
String[] mappings = configuredMappings.split(";");
Collections.addAll(viewMappings, mappings);
}
}
for (String viewMapping : viewMappings) {
viewMapping = viewMapping.trim();
if (viewMapping.startsWith("*")) {
String faceletExtension = viewMapping.substring(1);
if (!faceletExtensions.contains(faceletExtension)) {
faceletExtensions.add(faceletExtension);
}
}
else if (viewMapping.endsWith("*")) {
String faceletPathMapping = viewMapping.substring(0, viewMapping.length() - 1);
if (!faceletPathMappings.contains(faceletPathMapping)) {
faceletPathMappings.add(faceletPathMapping);
}
}
}
for (String faceletPathMapping : faceletPathMappings) {
if (resourceId.startsWith(faceletPathMapping)) {
logger.trace("MATCHED FACELET PATH MAPPING resourceId=[{0}] faceletPathMapping=[{1}]", resourceId,
faceletPathMapping);
faceletDocument = true;
break;
}
}
for (String faceletExtension : faceletExtensions) {
if (resourceId.contains(faceletExtension)) {
logger.trace("MATCHED FACELET EXTENSION MAPPING resourceId=[{0}] faceletExtension=[{1}] ", resourceId,
faceletExtension);
faceletDocument = true;
break;
}
}
if (!faceletDocument) {
faceletDocument = isFaceletsVDL(resourceId);
}
return faceletDocument;
}
@Override
public boolean isSelfReferencing(FacesContext facesContext, String resourceId) {
return false;
}
public boolean isValidLibraryName(String libraryName) {
boolean validLibraryName = true;
if (excludeLibraryPatterns != null) {
for (Pattern excludeLibraryPattern : excludeLibraryPatterns) {
Matcher matcher = excludeLibraryPattern.matcher(libraryName);
if (matcher.matches()) {
validLibraryName = false;
logger.trace("MATCHED LIBRARY NAME EXCLUSION PATTERN libraryName=[{0}] matcher=[{1}]", libraryName,
matcher);
break;
}
}
}
return validLibraryName;
}
public boolean isValidResourceName(String resourceName) {
boolean validResourceName = true;
if (excludeResourcePatterns != null) {
for (Pattern excludeResourcePattern : excludeResourcePatterns) {
Matcher matcher = excludeResourcePattern.matcher(resourceName);
if (matcher.matches()) {
validResourceName = false;
logger.trace("MATCHED RESOURCE NAME EXCLUSION PATTERN resourceName=[{0}] matcher=[{1}] ",
resourceName, matcher);
break;
}
}
}
return validResourceName;
}
protected boolean isFaceletsVDL(String viewId) {
boolean faceletsVDL = false;
ViewDeclarationLanguageFactory viewDeclarationLanguageFactory = (ViewDeclarationLanguageFactory) FactoryFinder
.getFactory(FactoryFinder.VIEW_DECLARATION_LANGUAGE_FACTORY);
ViewDeclarationLanguage viewDeclarationLanguage = viewDeclarationLanguageFactory.getViewDeclarationLanguage(
viewId);
if (viewDeclarationLanguage != null) {
faceletsVDL = viewDeclarationLanguage.getId().equals(
ViewDeclarationLanguage.FACELETS_VIEW_DECLARATION_LANGUAGE_ID);
if (faceletsVDL) {
logger.trace("MATCHED FACELETS VDL viewId=[{0}]", viewId);
}
}
return faceletsVDL;
}
}