Skip to content

Commit

Permalink
LPS-27741 Add security by plugin context execution to template engines
Browse files Browse the repository at this point in the history
- 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 14, 2012
1 parent b2a65f0 commit 90c4e85
Show file tree
Hide file tree
Showing 16 changed files with 845 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,6 +39,7 @@
import java.io.IOException;

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

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

_classLoaderHelperUtilities.clear();

_classLoaderHelperUtilities = null;

_configuration.clearEncodingMap();
_configuration.clearSharedVariables();
_configuration.clearTemplateCache();
Expand All @@ -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,
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@

import freemarker.ext.beans.BeansWrapper;

import freemarker.template.utility.ObjectConstructor;

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

Expand All @@ -52,7 +50,7 @@ public Map<String, Object> getHelperUtilities() {

// Object util

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

// Portlet preferences

Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}

}
Original file line number Diff line number Diff line change
@@ -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);
}
}

}
Original file line number Diff line number Diff line change
@@ -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;

}
Loading

0 comments on commit 90c4e85

Please sign in to comment.