/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Jetspeed" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache" or
* "Apache Jetspeed", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.jetspeed.portal.security.portlets;
// Jetspeed
import org.apache.jetspeed.om.security.JetspeedUser;
import org.apache.jetspeed.portal.Portlet;
import org.apache.jetspeed.portal.PortletState;
import org.apache.jetspeed.portal.PortletConfig;
import org.apache.jetspeed.portal.PortletException;
import org.apache.jetspeed.portal.PortletInstance;
import org.apache.jetspeed.services.portletcache.Cacheable;
import org.apache.jetspeed.services.security.PortalResource;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.util.template.JetspeedLink;
import org.apache.jetspeed.util.template.JetspeedLinkFactory;
import org.apache.jetspeed.util.MimeType;
import org.apache.jetspeed.services.PortletStats;
// Turbine imports
import org.apache.turbine.util.Log;
import org.apache.turbine.util.RunData;
import org.apache.turbine.services.localization.Localization;
// ECS
import org.apache.ecs.ConcreteElement;
import org.apache.jetspeed.util.JetspeedClearElement;
/**
<p>
This object is used to wrap a Portlet, ensuring that access control rules are enforced.
</p>
@author <A HREF="mailto:sgala@apache.org">Santiago Gala</A>
@version $Id: PortletWrapper.java,v 1.20 2003/03/13 01:08:11 morciuch Exp $
*/
public class PortletWrapper implements Portlet
{
/*
* The portlet we are wrapping
*/
private Portlet wrappedPortlet = null;
private PortalResource portalResource = null;
private ConcreteElement content = null;
public PortletWrapper(Portlet inner)
{
wrappedPortlet = inner;
portalResource = new PortalResource(wrappedPortlet);
}
/**
*/
public final String getName()
{
//This means name is accessible for every Portlet
return wrappedPortlet.getName();
}
/**
*/
public final void setName(String name)
{
//if we want to secure this, we need a context for the check
wrappedPortlet.setName(name);
}
/**
*/
public final PortletConfig getPortletConfig()
{
return wrappedPortlet.getPortletConfig();
}
/**
*/
public final void setPortletConfig(PortletConfig pc)
{
//if we want to secure this, we need a context for the check
wrappedPortlet.setPortletConfig(pc);
}
/**
*/
public ConcreteElement getContent(RunData rundata)
{
if (checkPermission(rundata, JetspeedSecurity.PERMISSION_VIEW))
{
if (PortletStats.isEnabled())
{
long start = System.currentTimeMillis();
content = wrappedPortlet.getContent(rundata);
long time = System.currentTimeMillis() - start; // time it took to get the content for this portlet
PortletStats.logAccess(rundata, this, PortletStats.ACCESS_OK, time);
} else {
content = wrappedPortlet.getContent(rundata);
}
return content;
}
else
{
if (PortletStats.isEnabled())
{
PortletStats.logAccess(rundata, this, PortletStats.ACCESS_DENIED);
}
return new JetspeedClearElement(Localization.getString("SECURITY_NO_ACCESS_TO_PORTLET"));
}
}
/**
Provide a description within PML if the user has specified one.
@return a null entry if the user hasn't defined anything
*/
public String getDescription()
{
return wrappedPortlet.getDescription();
}
public String getDescription(String instanceDescription)
{
return wrappedPortlet.getDescription(instanceDescription);
}
/**
*/
public void setDescription(String description)
{
wrappedPortlet.setDescription(description);
}
/**
* @see Portlet#getImage
*/
public String getImage(String instanceImage)
{
return wrappedPortlet.getImage(instanceImage);
}
/**
* @see Portlet#setImge
*/
public void setImage(String image)
{
wrappedPortlet.setImage(image);
}
/**
* @see Portlet#getTitle
*/
public String getTitle()
{
/* FIXME, no rundata here if( !checkPermission(rundata,
JetspeedSecurity.PERMISSION_VIEW ) )
{ */
return wrappedPortlet.getTitle();
/* } */
}
/**
* @see Portlet#getImage
*/
public String getTitle(String instanceTitle)
{
return wrappedPortlet.getTitle(instanceTitle);
}
/**
Set the title for this Portlet
*/
public void setTitle(String title)
{
/* FIXME, no rundata here if( !checkPermission(rundata,
JetspeedSecurity.PERMISSION_CUSTOMIZE ) )
{ */
wrappedPortlet.setTitle(title);
/* } */
}
/**
*/
public boolean getAllowEdit(RunData rundata)
{
return checkPermission(rundata, JetspeedSecurity.PERMISSION_CUSTOMIZE);
}
/**
*/
public boolean getAllowMaximize(RunData rundata)
{
return checkPermission(rundata, JetspeedSecurity.PERMISSION_MAXIMIZE);
}
/**
By default don't provide any initialization
*/
public void init() throws PortletException
{
/* FIXME, no rundata here if( !checkPermission(rundata,
JetspeedSecurity.PERMISSION_CUSTOMIZE) )
{ */
wrappedPortlet.init();
/* } */
}
/**
@see Portlet#getCreationTime
*/
public long getCreationTime()
{
/* FIXME, no rundata here if( !checkPermission(rundata,
JetspeedSecurity.PERMISSION_VIEW) )
{ */
return wrappedPortlet.getCreationTime();
/* } */
}
/**
@see Portlet#setCreationTime
*/
public void setCreationTime(long creationTime)
{
/* FIXME, no rundata here if( !checkPermission(rundata,
JetspeedSecurity.PERMISSION_CUSTOMIZE) )
{ */
wrappedPortlet.setCreationTime(creationTime);
}
/**
@see Portlet#supportsType
*/
public boolean supportsType(MimeType mimeType)
{
/* FIXME, no rundata here if( !checkPermission(rundata,
JetspeedSecurity.PERMISSION_VIEW) )
{ */
return wrappedPortlet.supportsType(mimeType);
/* } */
}
/**
* Utility method for checking Permissions on myself.
* @param rundata A rundata Object
* @param permissionName String the name of the Permission requested
* @return boolean is it granted?
*/
protected boolean checkPermission(RunData rundata, String permissionName)
{
try
{
JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);
portalResource.setOwner(jsLink.getUserName());
JetspeedLinkFactory.putInstance(jsLink);
}
catch (Exception e)
{
Log.warn(e.toString());
portalResource.setOwner(null);
}
if (Log.getLogger().isDebugEnabled())
{
Log.debug("checking for Portlet permission: "
+ permissionName
+ " for portlet: "
+ wrappedPortlet.getName()
+ " Owner = "
+ portalResource.getOwner());
}
return JetspeedSecurity.checkPermission((JetspeedUser) rundata.getUser(),
portalResource,
permissionName);
}
// utility methods
/**
Returns TRUE if the title bar in should be displayed. The title bar includes
the portlet title and action buttons.
NOTE(FIXME) Not in Portlet interface. Called a la Bean from Velocity.
@param rundata A RunData object
*/
public boolean isShowTitleBar(RunData rundata)
{
if (wrappedPortlet.getPortletConfig() != null)
{
// Parameter can exist in PSML or <portlet-entry>
return Boolean.valueOf(wrappedPortlet.getPortletConfig().getInitParameter("_showtitlebar", "true")).booleanValue();
}
return getAttribute("_showtitlebar", "true", rundata).equals("true");
}
/**
Retrieve a portlet attribute from persistent storage
@param attrName The attribute to retrieve
@parm attrDefValue The value if the attr doesn't exists
@param rundata A RunData object
@return The attribute value
*/
public String getAttribute(String attrName, String attrDefValue, RunData rundata)
{
if (checkPermission(rundata, JetspeedSecurity.PERMISSION_VIEW))
{
return wrappedPortlet.getAttribute(attrName, attrDefValue, rundata);
}
else
{
//FIXME: for the moment we will allow this call to succeed...
//throw new TurbineRuntimeException( "Security check failed" );
return wrappedPortlet.getAttribute(attrName, attrDefValue, rundata);
}
}
/**
* Sets a portlet attribute to persistent storage
*
* @param attrName The attribute to retrieve
* @param attrValue The value
* @param rundata A RunData object
*/
public void setAttribute(String attrName, String attrValue, RunData rundata)
{
if (checkPermission(rundata, JetspeedSecurity.PERMISSION_VIEW))
{
wrappedPortlet.setAttribute(attrName, attrValue, rundata);
}
else
{
//FIXME: for the moment we will allow this call to succeed...
//throw new TurbineRuntimeException( "Security check failed" );
wrappedPortlet.setAttribute(attrName, attrValue, rundata);
}
}
/**
* Gets the portlet instance associated with this portlet.
*
* @param rundata A RunData object
* @return PortletInstance
*/
public PortletInstance getInstance(RunData rundata)
{
return wrappedPortlet.getInstance(rundata);
}
/**
* <p>Return an instance of one of the classes in this package
* making tests before calling the wrapped portlet</p>
* <p>Different wrapper classes must be used with the current API
* depending on the interfaces implemented by the portlet. :-(</p>
*
*/
public static Portlet wrap(Portlet aPortlet)
{
//SGP Security test
if (aPortlet instanceof PortletState)
{
if (aPortlet instanceof Cacheable)
{
return new CacheableStatefulPortletWrapper(aPortlet);
}
return new StatefulPortletWrapper(aPortlet);
}
if (aPortlet instanceof Cacheable)
{
return new CacheablePortletWrapper(aPortlet);
}
return new PortletWrapper(aPortlet);
}
public String getID()
{
return wrappedPortlet.getID();
}
public void setID(String id)
{
wrappedPortlet.setID(id);
}
/**
* @return true if the portlet does its own customization
*/
public boolean providesCustomization()
{
return wrappedPortlet.providesCustomization();
}
public Portlet getPortlet()
{
return wrappedPortlet;
}
}