/**
* Copyright (c) 2000-present 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.security.lang;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.security.pacl.DoPrivileged;
import com.liferay.portal.kernel.util.AggregateClassLoader;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.kernel.util.ReflectionUtil;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.HashSet;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* @author Raymond Augé
*/
public class DoPrivilegedFactory
extends InstantiationAwareBeanPostProcessorAdapter
implements ApplicationContextAware {
public static boolean isEarlyBeanReference(String beanName) {
return _earlyBeanReferenceNames.contains(beanName);
}
public static <T> T wrap(T bean) {
Class<?> clazz = bean.getClass();
if (clazz.isPrimitive()) {
return bean;
}
Package pkg = clazz.getPackage();
if (pkg != null) {
String packageName = pkg.getName();
if (packageName.startsWith("java.")) {
return bean;
}
}
Class<?>[] interfaces = ReflectionUtil.getInterfaces(bean);
if (interfaces.length <= 0) {
return bean;
}
return AccessController.doPrivileged(
new BeanPrivilegedAction<T>(bean, interfaces));
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName)
throws BeansException {
if (_isWrap(bean, beanName)) {
_earlyBeanReferenceNames.add(beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (!SecurityManagerUtil.ENABLED) {
return bean;
}
if (!_isWrap(bean, beanName)) {
return bean;
}
if (isEarlyBeanReference(beanName)) {
if (_log.isDebugEnabled()) {
_log.debug("Postpone wrapping early reference of " + beanName);
}
return bean;
}
if (_log.isDebugEnabled()) {
Class<?> clazz = bean.getClass();
_log.debug(
"Wrapping calls to bean " + beanName + " of type " + clazz +
" with access controller checking");
}
return wrap(bean);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
_classLoader = AggregateClassLoader.getAggregateClassLoader(
PortalClassLoaderUtil.getClassLoader(),
applicationContext.getClassLoader());
}
private boolean _isDoPrivileged(Class<?> beanClass) {
DoPrivileged doPrivileged = beanClass.getAnnotation(DoPrivileged.class);
while ((doPrivileged == null) &&
(beanClass = beanClass.getSuperclass()) != null) {
doPrivileged = beanClass.getAnnotation(DoPrivileged.class);
}
if (doPrivileged != null) {
return true;
}
return false;
}
private boolean _isFinderOrPersistence(String beanName) {
if (beanName.endsWith(_BEAN_NAME_SUFFIX_FINDER) ||
beanName.endsWith(_BEAN_NAME_SUFFIX_PERSISTENCE)) {
return true;
}
return false;
}
private boolean _isWrap(Object bean, String beanName) {
Class<?> clazz = bean.getClass();
if (_isDoPrivileged(clazz) || _isFinderOrPersistence(beanName)) {
return true;
}
return false;
}
private static final String _BEAN_NAME_SUFFIX_FINDER = "Finder";
private static final String _BEAN_NAME_SUFFIX_PERSISTENCE = "Persistence";
private static final Log _log = LogFactoryUtil.getLog(
DoPrivilegedFactory.class);
private static ClassLoader _classLoader =
DoPrivilegedFactory.class.getClassLoader();
private static final Set<String> _earlyBeanReferenceNames = new HashSet<>();
private static class BeanPrivilegedAction<T>
implements PrivilegedAction<T> {
public BeanPrivilegedAction(T bean, Class<?>[] interfaces) {
_bean = bean;
_interfaces = ArrayUtil.append(interfaces, DoPrivilegedBean.class);
}
@Override
public T run() {
try {
return (T)ProxyUtil.newProxyInstance(
_classLoader, _interfaces, new DoPrivilegedHandler(_bean));
}
catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn(e, e);
}
}
return _bean;
}
private final T _bean;
private final Class<?>[] _interfaces;
}
}