Skip to content
Permalink
Browse files

LPS-27741 Add security by plugin context execution to template engines

- We have to initialize/destroy a new template context specific to each plugin (keyed by ClassLoader of the plugin)
- Add/Replaced helper utilities to support classloading control (and access to classes/packages) within templates
  • Loading branch information...
rotty3000 authored and brianchandotcom committed Jun 8, 2012
1 parent b2a65f0 commit 90c4e85a8f8135f069f3f05e4d54a77704769f91
@@ -21,6 +21,7 @@
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.servlet.ServletContextPool;
import com.liferay.portal.kernel.template.TemplateManagerUtil;
import com.liferay.portal.kernel.util.BasePortalLifecycle;
import com.liferay.portal.kernel.util.HttpUtil;
import com.liferay.portal.kernel.util.PortalLifecycle;
@@ -105,7 +106,11 @@ public void fireUndeployEvent(HotDeployEvent hotDeployEvent) {
_deployedServletContextNames.remove(
hotDeployEvent.getServletContextName());

PACLPolicyManager.unregister(hotDeployEvent.getContextClassLoader());
ClassLoader classLoader = hotDeployEvent.getContextClassLoader();

TemplateManagerUtil.destroy(classLoader);

PACLPolicyManager.unregister(classLoader);
}

public void registerListener(HotDeployListener hotDeployListener) {
@@ -22,6 +22,10 @@
import com.liferay.portal.kernel.template.TemplateException;
import com.liferay.portal.kernel.template.TemplateManager;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
import com.liferay.portal.security.pacl.PACLPolicy;
import com.liferay.portal.security.pacl.PACLPolicyManager;
import com.liferay.portal.template.RestrictedTemplate;
import com.liferay.portal.template.TemplateContextHelper;
import com.liferay.portal.util.PropsValues;
@@ -35,6 +39,7 @@
import java.io.IOException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* @author Mika Koivisto
@@ -63,6 +68,10 @@ public void destroy() {
return;
}

_classLoaderHelperUtilities.clear();

_classLoaderHelperUtilities = null;

_configuration.clearEncodingMap();
_configuration.clearSharedVariables();
_configuration.clearTemplateCache();
@@ -84,11 +93,55 @@ public void destroy() {
_templateContextHelper = null;
}

public void destroy(ClassLoader classLoader) {
_classLoaderHelperUtilities.remove(classLoader);
}

public Template getTemplate(
String templateId, String templateContent, String errorTemplateId,
String errorTemplateContent, TemplateContextType templateContextType) {

if (templateContextType.equals(TemplateContextType.EMPTY)) {
if (templateContextType.equals(TemplateContextType.CLASS_LOADER)) {

// This template will have all of its utilities initialized within
// the class loader of the current thread

ClassLoader contextClassLoader =
PACLClassLoaderUtil.getContextClassLoader();

PACLPolicy threadLocalPACLPolicy =
PortalSecurityManagerThreadLocal.getPACLPolicy();

PACLPolicy contextClassLoaderPACLPolicy =
PACLPolicyManager.getPACLPolicy(contextClassLoader);

try {
PortalSecurityManagerThreadLocal.setPACLPolicy(
contextClassLoaderPACLPolicy);

Map<String, Object> helperUtilities =
_classLoaderHelperUtilities.get(contextClassLoader);

if (helperUtilities == null) {
helperUtilities =
_templateContextHelper.getHelperUtilities();

_classLoaderHelperUtilities.put(
contextClassLoader, helperUtilities);
}

return new PACLFreeMarkerTemplate(
templateId, templateContent, errorTemplateId,
errorTemplateContent, helperUtilities, _configuration,
_templateContextHelper, _stringTemplateLoader,
contextClassLoaderPACLPolicy);
}
finally {
PortalSecurityManagerThreadLocal.setPACLPolicy(
threadLocalPACLPolicy);
}
}
else if (templateContextType.equals(TemplateContextType.EMPTY)) {
return new FreeMarkerTemplate(
templateId, templateContent, errorTemplateId,
errorTemplateContent, null, _configuration,
@@ -186,6 +239,8 @@ public void init() throws TemplateException {
_configuration.setDefaultEncoding(StringPool.UTF8);
_configuration.setLocalizedLookup(
PropsValues.FREEMARKER_ENGINE_LOCALIZED_LOOKUP);
_configuration.setNewBuiltinClassResolver(
new LiferayTemplateClassResolver());
_configuration.setObjectWrapper(new LiferayObjectWrapper());
_configuration.setTemplateLoader(multiTemplateLoader);
_configuration.setTemplateUpdateDelay(
@@ -217,6 +272,8 @@ public void setTemplateContextHelper(

private static Log _log = LogFactoryUtil.getLog(FreeMarkerManager.class);

private Map<ClassLoader, Map<String, Object>> _classLoaderHelperUtilities =
new ConcurrentHashMap<ClassLoader, Map<String, Object>>();
private Configuration _configuration;
private Map<String, Object> _restrictedHelperUtilities;
private Map<String, Object> _standardHelperUtilities;
@@ -28,8 +28,6 @@

import freemarker.ext.beans.BeansWrapper;

import freemarker.template.utility.ObjectConstructor;

import java.util.Map;
import java.util.Set;

@@ -52,7 +50,7 @@

// Object util

helperUtilities.put("objectUtil", new ObjectConstructor());
helperUtilities.put("objectUtil", new LiferayObjectConstructor());

// Portlet preferences

@@ -0,0 +1,60 @@
/**
* Copyright (c) 2000-2012 Liferay, Inc. 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.liferay.portal.freemarker;

import com.liferay.portal.security.pacl.PACLClassLoaderUtil;

import freemarker.ext.beans.BeansWrapper;

import freemarker.template.TemplateMethodModelEx;
import freemarker.template.TemplateModelException;

import java.util.List;

/**
* @author Raymond Augé
*/
public class LiferayObjectConstructor implements TemplateMethodModelEx {

public Object exec(@SuppressWarnings("rawtypes") List arguments)
throws TemplateModelException {

if (arguments.isEmpty()) {
throw new TemplateModelException(
"This method must have at least one argument as the name of " +
"the class to instantiate");
}

Class<?> clazz = null;

try {
String className = String.valueOf(arguments.get(0));

clazz = Class.forName(
className, true, PACLClassLoaderUtil.getContextClassLoader());
}
catch (Exception e) {
throw new TemplateModelException(e.getMessage());
}

BeansWrapper beansWrapper = BeansWrapper.getDefaultInstance();

Object object = beansWrapper.newInstance(
clazz, arguments.subList(1, arguments.size()));

return beansWrapper.wrap(object);
}

}
@@ -0,0 +1,74 @@
/**
* Copyright (c) 2000-2012 Liferay, Inc. 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.liferay.portal.freemarker;

import com.liferay.portal.security.pacl.PACLClassLoaderUtil;
import com.liferay.portal.util.PropsValues;

import freemarker.core.Environment;
import freemarker.core.TemplateClassResolver;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.utility.ObjectConstructor;

/**
* @author Raymond Augé
*/
public class LiferayTemplateClassResolver implements TemplateClassResolver {

public Class<?> resolve(
String className, Environment environment, Template template)
throws TemplateException {

if (className.equals(ObjectConstructor.class.getName())) {
throw new TemplateException(
"Instantiating " + className + " is not allowed in the " +
"template for security reasons",
environment);
}

for (String restrictedClassName :
PropsValues.FREEMARKER_ENGINE_RESTRICTED_CLASSES) {

if (className.equals(restrictedClassName)) {
throw new TemplateException(
"Instantiating " + className + " is not allowed in the " +
"template for security reasons",
environment);
}
}

for (String restrictedPackageName :
PropsValues.FREEMARKER_ENGINE_RESTRICTED_PACKAGES) {

if (className.startsWith(restrictedPackageName)) {
throw new TemplateException(
"Instantiating " + className + " is not allowed in the " +
"template for security reasons",
environment);
}
}

try {
return Class.forName(
className, true, PACLClassLoaderUtil.getContextClassLoader());
}
catch (Exception e) {
throw new TemplateException(e, environment);
}
}

}
@@ -0,0 +1,65 @@
/**
* Copyright (c) 2000-2012 Liferay, Inc. 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.liferay.portal.freemarker;

import com.liferay.portal.kernel.template.TemplateException;
import com.liferay.portal.security.lang.PortalSecurityManagerThreadLocal;
import com.liferay.portal.security.pacl.PACLPolicy;
import com.liferay.portal.template.TemplateContextHelper;

import freemarker.template.Configuration;

import java.io.Writer;

import java.util.Map;

/**
* @author Raymond Augé
*/
public class PACLFreeMarkerTemplate extends FreeMarkerTemplate {

public PACLFreeMarkerTemplate(
String templateId, String templateContent, String errorTemplateId,
String errorTemplateContent, Map<String, Object> context,
Configuration configuration,
TemplateContextHelper templateContextHelper,
StringTemplateLoader stringTemplateLoader, PACLPolicy paclPolicy) {

super(
templateId, templateContent, errorTemplateId, errorTemplateContent,
context, configuration, templateContextHelper,
stringTemplateLoader);

_paclPolicy = paclPolicy;
}

@Override
public boolean processTemplate(Writer writer) throws TemplateException {
PACLPolicy initialPolicy =
PortalSecurityManagerThreadLocal.getPACLPolicy();

try {
PortalSecurityManagerThreadLocal.setPACLPolicy(_paclPolicy);

return super.processTemplate(writer);
}
finally {
PortalSecurityManagerThreadLocal.setPACLPolicy(initialPolicy);
}
}

private PACLPolicy _paclPolicy;

}

0 comments on commit 90c4e85

Please sign in to comment.
You can’t perform that action at this time.