You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by James Carman <ja...@carmanconsulting.com> on 2006/06/08 04:37:53 UTC

Tapestry/Acegi Integration...

All,

I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
application now uses Acegi to secure the CreateMessage page (using a
@Secured("ROLE_USER") annotation).  By no means is this the final version.
I just wanted to get it in front of some folks to see what they thought.
Enjoy!

James



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
Scott,

Thank you for your kind words.  No, it's not quite complete.  I plan on
adding in ACL support and other stuff.  I just wanted to get a "proof of
concept" out there.  The AuthenticationManager and the AccessDecisionManager
will be set automatically by HiveMind, by including the hivemind-acegi
module jar file on the classpath.  There are certain aspects of the Acegi
support that are not exactly specific to Tapestry, so I abstracted them out
into their own library so that others could use it.  The tapernate-example
application uses the Tapestry/Acegi integration.  It's available via SVN at:

www.carmanconsulting.com/svn/public/tapernate-example/trunk

You can build it using Maven2 and it will automagically download everything
it needs (including the hivemind-acegi stuff).  I need to add in some other
Maven2 repositories into the pom.xml file so that some of the specification
jars (JTA, JPA, etc.) will be downloaded automatically without having to
manually copy stuff into your local repo.

James


-----Original Message-----
From: Scott Russell [mailto:scottr72@gmail.com] 
Sent: Saturday, June 17, 2006 11:04 PM
To: users@tapestry.apache.org
Subject: Re: Tapestry/Acegi Integration...

Hi James,

I took a look at the Tapestry-Acegi integration project at 
http://www.carmanconsulting.com/tapestry-acegi/ . It looks very nice, 
certainly a cleaner integration than what I have used before. 

I am just wondering how complete it is. Looking through the code, it appears

that the configuration is incomplete, at least, as much as I can see the 
SecurityUtils service-point seems not to have the authenticationManager or 
accessDecisionManager properties set.

Do you have any examples for how to use this in one's app, and override or
set 
the properties on the service-points like SecurityUtils and 
ExceptionTranslationFilter? 

regards,
Scott

On Thursday 08 June 2006 12:37, James Carman wrote:
> All,
>
> I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
> application now uses Acegi to secure the CreateMessage page (using a
> @Secured("ROLE_USER") annotation).  By no means is this the final version.
> I just wanted to get it in front of some folks to see what they thought.
> Enjoy!
>
> James
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Tapestry/Acegi Integration...

Posted by Scott Russell <sc...@gmail.com>.
Hi James,

I took a look at the Tapestry-Acegi integration project at 
http://www.carmanconsulting.com/tapestry-acegi/ . It looks very nice, 
certainly a cleaner integration than what I have used before. 

I am just wondering how complete it is. Looking through the code, it appears 
that the configuration is incomplete, at least, as much as I can see the 
SecurityUtils service-point seems not to have the authenticationManager or 
accessDecisionManager properties set.

Do you have any examples for how to use this in one's app, and override or set 
the properties on the service-points like SecurityUtils and 
ExceptionTranslationFilter? 

regards,
Scott

On Thursday 08 June 2006 12:37, James Carman wrote:
> All,
>
> I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
> application now uses Acegi to secure the CreateMessage page (using a
> @Secured("ROLE_USER") annotation).  By no means is this the final version.
> I just wanted to get it in front of some folks to see what they thought.
> Enjoy!
>
> James
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
There are a few modules involved, all at JavaForge.  The hivemind-acegi and
hivemind-acegi-dao are located in the hivemind project.  The tapestry-acegi
module is located in the tapestry project.  The SVN URLs are as follows:

http://svn.javaforge.com/svn/hivemind/hivemind-acegi/trunk

http://svn.javaforge.com/svn/hivemind/hivemind-acegi-dao/trunk

http://svn.javaforge.com/svn/tapestry/tapestry-acegi/trunk

You can login using anonymous/anon.



-----Original Message-----
From: Henri Dupre [mailto:henri.dupre@gmail.com] 
Sent: Wednesday, June 07, 2006 11:04 PM
To: Tapestry users
Subject: Re: Tapestry/Acegi Integration...

That's fantastic! Where's the code?


On 6/7/06, James Carman <ja...@carmanconsulting.com> wrote:
>
> All,
>
> I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
> application now uses Acegi to secure the CreateMessage page (using a
> @Secured("ROLE_USER") annotation).  By no means is this the final version.
> I just wanted to get it in front of some folks to see what they thought.
> Enjoy!
>
> James
>
>
>
> --
> Thanks,
>
> Henri.



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Tapestry/Acegi Integration...

Posted by Henri Dupre <he...@gmail.com>.
That's fantastic! Where's the code?


On 6/7/06, James Carman <ja...@carmanconsulting.com> wrote:
>
> All,
>
> I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
> application now uses Acegi to secure the CreateMessage page (using a
> @Secured("ROLE_USER") annotation).  By no means is this the final version.
> I just wanted to get it in front of some folks to see what they thought.
> Enjoy!
>
> James
>
>
>
> --
> Thanks,
>
> Henri.

RE: Tapestry/Acegi Integration...

Posted by bkbonner <br...@paraware.com>.
got in with 'anonymous' and 'anon'.
--
View this message in context: http://www.nabble.com/Tapestry-Acegi-Integration...-t1752611.html#a4847443
Sent from the Tapestry - User forum at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by bkbonner <br...@paraware.com>.
James,

I tried getting access to the SVN repository via javaforge using my
'bkbonner' ID, but was unable.  It said 'Tapernate project wasn't found'
when doing a search.  ???

I'm interested in the @Secured component you were discussing.  Is this out
in SVN?

p.s.  I see you're on maven ;)

Brian
--
View this message in context: http://www.nabble.com/Tapestry-Acegi-Integration...-t1752611.html#a4846956
Sent from the Tapestry - User forum at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Tapestry/Acegi Integration...

Posted by Andreas Bulling <sp...@phoenix.hadiko.de>.
On 09. Jun 2006 - 10:11:15, Gernot Stocker wrote:
| Hi,
| this sounds really great! Is there already a released jar file around which can 
| be just plugged in ;-) ?

At the moment you have to download the whole .war archive from
www.carmanconsulting.com/mvn/com/carmanconsulting/tapernate-example/0.1
and pick the needed jars from WEB-INF/lib manually.

I've already requested the jars to be released seperately from
the tapernate-example -> James is informed ;)

HTH,
  Andreas

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by Jonathan Barker <jo...@gmail.com>.
Hi,

I've now been lurking for two years.  I finally had a project where I could
use Tapestry... and Hibernate, and Spring, and Acegi...  So many hills to
climb...

Anyway, I put together an @Authorize component combining code from the
Tapestry @If component and the JSP taglib from Acegi.

As it stands, it behaves exactly as an @If, except that it takes
comma-separated lists of roles as parameters like the Acegi Auuthorize tag.
I also use @Else along with it - it hardly seemed necessary to come up with
a different AuthorizeElse component  I'm using it in production, and it
works beautifully.  I have also put together an AclAuthorize component for
instance-based security, if you are interested.

I would be happy to see this component included in a properly maintained
library under the Apache license.  At this point, I haven't even had a
chance to extract it into a library of my own or get back to it to clean up
the code and comments which include remnants of the taglib.

I haven't tried tapernate yet so I don't know if this is a simple drop-in.

  
Best regards,

Jonathan Barker


Code:
=====================================================

package ca.itstrategic.tls.ptpip.ui.tapestry.components;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.HiveMind;
import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IBinding;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.annotations.ComponentClass;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.services.DataSqueezer;
import org.apache.tapestry.web.WebContext;
import org.apache.tapestry.web.WebRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;

import diaphragma.tapspr.XWebApplicationContextUtils;

/**
 * @author jabarker
 * @version $Revision:  $
 */
@ComponentClass(allowInformalParameters=true, allowBody=true)
public abstract class Authorize extends AbstractFormComponent {

	@Parameter(required=false)
	public abstract String getIfAllGranted();
	@Parameter(required=false)
	public abstract String getIfAnyGranted();
	@Parameter(required=false)
	public abstract String getIfNotGranted();
	
	

	/**
	 * An implementation of {BaseComponent} that allows its
	 * body through if some authorizations are granted to the request's
principal.
	 * 
	 * <P>
	 * Only works with permissions that are subclasses of {@link
	 * org.acegisecurity.acl.basic.BasicAclEntry}.
	 * </p>
	 * 
	 * <p>
	 * One or more comma separate integer permissions are specified via
the
	 * <code>hasPermission</code> attribute. The tag will include its
body if
	 * <b>any</b> of the integer permissions have been granted to the
current
	 * <code>Authentication</code> (obtained from the
<code>SecurityContextHolder</code>).
	 * </p>
	 * 
	 * <p>
	 * For this class to operate it must be able to access the
application context
	 * via the <code>WebApplicationContextUtils</code> and locate an
{@link
	 * AclManager}. Application contexts have no need to have more than
one
	 * <code>AclManager</code> (as a provider-based implementation can
be used so
	 * that it locates a provider that is authoritative for the given
domain
	 * object instance), so the first <code>AclManager</code> located
will be
	 * used.
	 * </p>
	 *
	 * @author Ben Alex
	 */

    public final static String IF_VALUE_ATTRIBUTE =
"org.mb.tapestry.base.IfValue";

    @Parameter(required=false)
    public abstract IBinding getConditionValueBinding();

    @Parameter(required=false)
    public abstract boolean getVolatile();

    @Parameter(required=false)
    public abstract String getElement();

    @Parameter(required=false)
    public abstract IActionListener getListener();

    private boolean _rendering = false;

    private boolean _conditionValue;

    //~ Static fields/initializers
=============================================

    protected static final Log logger =
LogFactory.getLog(AclAuthorize.class);

    //~ Methods
================================================================

    @InjectObject("service:tapestry.globals.WebContext")
    public abstract WebContext getWebContext();

    @InjectObject("service:tapestry.globals.WebRequest")
    public abstract WebRequest getWebRequest();
    
    protected void renderComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
        boolean cycleRewinding = cycle.isRewinding();

        // form may be null if component is not located in a form
        IForm form = (IForm)
cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);

        // If the cycle is rewinding, but not this particular form,
        // then do nothing (don't even render the body).
        if (cycleRewinding && form != null && !form.isRewinding())
            return;

        // get the condition. work with a hidden field if necessary
        _conditionValue = evaluateCondition(cycle, form, cycleRewinding);
        _rendering = true;

        try
        {
            // call listener
            IActionListener listener = getListener();
            if (listener != null)
                listener.actionTriggered(this, cycle);

            // now render if condition is true
            if (_conditionValue)
            {
                String element = getElement();

                boolean render = !cycleRewinding &&
HiveMind.isNonBlank(element);

                if (render)
                {
                    writer.begin(element);
                    renderInformalParameters(writer, cycle);
                }

                renderBody(writer, cycle);

                if (render)
                    writer.end(element);
            }
        }
        finally
        {
            _rendering = false;
        }

        cycle.setAttribute(IF_VALUE_ATTRIBUTE, new
Boolean(_conditionValue));
    }

    protected boolean evaluateCondition(IRequestCycle cycle, IForm form,
boolean cycleRewinding)
    {
        boolean condition;

        if (form == null || getVolatile())
        {
            condition = checkPermission();
        }
        else
        {
            // we are in a form and we care -- load/store the condition in a
hidden field
            String name = form.getElementId(this);

            if (!cycleRewinding)
            {
                condition = checkPermission();
                writeValue(form, name, condition);
            }
            else
            {
                condition = readValue(cycle, name);
            }
        }

        // write condition value if parameter is bound
        IBinding conditionValueBinding = getConditionValueBinding();
        if (conditionValueBinding != null)
            conditionValueBinding.setObject(new Boolean(condition));

        return condition;
    }

    private void writeValue(IForm form, String name, boolean value)
    {
        String externalValue;

        Object booleanValue = new Boolean(value);
        try
        {
            externalValue = getDataSqueezer().squeeze(booleanValue);
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-value",
                    booleanValue), this, null, ex);
        }

        form.addHiddenValue(name, externalValue);
    }

    private boolean readValue(IRequestCycle cycle, String name)
    {
        String submittedValue = cycle.getParameter(name);

        try
        {
            Object valueObject =
getDataSqueezer().unsqueeze(submittedValue);
            if (!(valueObject instanceof Boolean))
                throw new ApplicationRuntimeException(Tapestry.format(
                        "If.invalid-condition-type",
                        submittedValue));

            return ((Boolean) valueObject).booleanValue();
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-string",
                    submittedValue), this, null, ex);
        }
    }

    public abstract DataSqueezer getDataSqueezer();

    public boolean isDisabled()
    {
        return false;
    }

    /**
     * Returns the value of the condition
     * 
     * @return the condition value
     */
    public boolean getConditionValue()
    {
        if (!_rendering)
            throw Tapestry.createRenderOnlyPropertyException(this,
"conditionValue");

        return _conditionValue;
    }

    // Do nothing in those methods, but make the JVM happy
    protected void renderFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    /**
     * For component can not take focus.
     */
    protected boolean getCanTakeFocus()
    {
        return false;
    }

    @SuppressWarnings("unchecked")
	private boolean checkPermission(){
    		String ifAllGranted = getIfAllGranted();
    		String ifAnyGranted = getIfAnyGranted();
    		String ifNotGranted = getIfNotGranted();
    		
            if (((null == ifAllGranted) || "".equals(ifAllGranted))
                    && ((null == ifAnyGranted) || "".equals(ifAnyGranted))
                    && ((null == ifNotGranted) || "".equals(ifNotGranted)))
{
                    return false;
                }
            

            final Collection granted = getPrincipalAuthorities();

            if ((null != ifNotGranted) && !"".equals(ifNotGranted)) {
                Set grantedCopy = retainAll(granted,
                        parseAuthoritiesString(ifNotGranted));

                if (!grantedCopy.isEmpty()) {
                    return false;
                }
            }

            if ((null != ifAllGranted) && !"".equals(ifAllGranted)) {
                if
(!granted.containsAll(parseAuthoritiesString(ifAllGranted))) {
                    return false;
                }
            }

            if ((null != ifAnyGranted) && !"".equals(ifAnyGranted)) {
                Set grantedCopy = retainAll(granted,
                        parseAuthoritiesString(ifAnyGranted));

                if (grantedCopy.isEmpty()) {
                    return false;
                }
            }

            return true;

            
            
//=========    		
	    }

	    /**
	     * Allows test cases to override where application context
obtained from.
	     *
	     * @param pageContext so the <code>ServletContext</code> can be
accessed as
	     *        required by Spring's
<code>WebApplicationContextUtils</code>
	     *
	     * @return the Spring application context (never
<code>null</code>)
	     */
	    protected ApplicationContext getContext(){
	    	return
XWebApplicationContextUtils.getRequiredWebApplicationContext(getWebContext()
);
	    }

	    private Collection getPrincipalAuthorities() {
//	    	SecurityContext sc = (SecurityContext)
getWebRequest().getSession(false).getAttribute(org.acegisecurity.context.Htt
pSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
	    	Authentication currentUser = null;
//			if(sc != null)
//			    currentUser = sc.getAuthentication();
	        currentUser =
SecurityContextHolder.getContext().getAuthentication();

	        if (null == currentUser) {
	            return Collections.EMPTY_LIST;
	        }

	        if ((null == currentUser.getAuthorities())
	            || (currentUser.getAuthorities().length < 1)) {
	            return Collections.EMPTY_LIST;
	        }

	        Collection granted =
Arrays.asList(currentUser.getAuthorities());
	        return granted;
	    }

	    @SuppressWarnings("unchecked")
		private Set authoritiesToRoles(Collection c) {
	        Set target = new HashSet();

	        for (Iterator iterator = c.iterator(); iterator.hasNext();)
{
	            GrantedAuthority authority = (GrantedAuthority)
iterator.next();

	            if (null == authority.getAuthority()) {
	                throw new IllegalArgumentException(
	                    "Cannot process GrantedAuthority objects which
return null from getAuthority() - attempting to process "
	                    + authority.toString());
	            }

	            target.add(authority.getAuthority());
	        }

	        return target;
	    }

	    @SuppressWarnings("unchecked")
		private Set parseAuthoritiesString(String
authorizationsString) {
	        final Set requiredAuthorities = new HashSet();
	        final String[] authorities = StringUtils
	            .commaDelimitedListToStringArray(authorizationsString);

	        for (int i = 0; i < authorities.length; i++) {
	            String authority = authorities[i];

	         // Remove the role's whitespace characters without
depending on JDK 1.4+ 
	         // Includes space, tab, new line, carriage return and form
feed. 
	         String role = StringUtils.replace(authority, " ", ""); 
	         role = StringUtils.replace(role, "\t", ""); 
	         role = StringUtils.replace(role, "\r", ""); 
	         role = StringUtils.replace(role, "\n", ""); 
	         role = StringUtils.replace(role, "\f", ""); 

	         requiredAuthorities.add(new GrantedAuthorityImpl(role));
	        }

	        return requiredAuthorities;
	    }

	    /**
	     * Find the common authorities between the current
authentication's {@link
	     * GrantedAuthority} and the ones that have been specified in
the tag's
	     * ifAny, ifNot or ifAllGranted attributes.
	     * 
	     * <p>
	     * We need to manually iterate over both collections, because
the granted
	     * authorities might not implement {@link Object#equals(Object)}
and
	     * {@link Object#hashCode()} in the same way as {@link
	     * GrantedAuthorityImpl}, thereby invalidating {@link
	     * Collection#retainAll(java.util.Collection)} results.
	     * </p>
	     * 
	     * <p>
	     * <strong>CAVEAT</strong>:  This method <strong>will
not</strong> work if
	     * the granted authorities returns a <code>null</code> string as
the
	     * return value of {@link
	     * org.acegisecurity.GrantedAuthority#getAuthority()}.
	     * </p>
	     * 
	     * <p>
	     * Reported by rawdave, on Fri Feb 04, 2005 2:11 pm in the Acegi
Security
	     * System for Spring forums.
	     * </p>
	     *
	     * @param granted The authorities granted by the authentication.
May be any
	     *        implementation of {@link GrantedAuthority} that does
	     *        <strong>not</strong> return <code>null</code> from
{@link
	     *        org.acegisecurity.GrantedAuthority#getAuthority()}.
	     * @param required A {@link Set} of {@link
GrantedAuthorityImpl}s that have
	     *        been built using ifAny, ifAll or ifNotGranted.
	     *
	     * @return A set containing only the common authorities between
	     *         <var>granted</var> and <var>required</var>.
	     *
	     * @see <a
	     *
href="http://forum.springframework.org/viewtopic.php?t=3367">authz:authorize
	     *      ifNotGranted not behaving as expected</a>
	     */
	    @SuppressWarnings("unchecked")
		private Set retainAll(final Collection granted, final Set
required) {
	        Set grantedRoles = authoritiesToRoles(granted);
	        Set requiredRoles = authoritiesToRoles(required);
	        grantedRoles.retainAll(requiredRoles);

	        return rolesToAuthorities(grantedRoles, granted);
	    }

	    @SuppressWarnings("unchecked")
		private Set rolesToAuthorities(Set grantedRoles, Collection
granted) {
	        Set target = new HashSet();

	        for (Iterator iterator = grantedRoles.iterator();
iterator.hasNext();) {
	            String role = (String) iterator.next();

	            for (Iterator grantedIterator = granted.iterator();
	                grantedIterator.hasNext();) {
	                GrantedAuthority authority = (GrantedAuthority)
grantedIterator
	                    .next();

	                if (authority.getAuthority().equals(role)) {
	                    target.add(authority);

	                    break;
	                }
	            }
	        }

	        return target;
	    }

//========================================================	
	/**
	 * 
	 */
	public Authorize() {
		super();
		// TODO Auto-generated constructor stub
	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.AbstractFormComponent#getForm()
	 */
	@Override
	public IForm getForm() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see
org.apache.tapestry.form.AbstractFormComponent#setForm(org.apache.tapestry.I
Form)
	 */
	@Override
	public void setForm(IForm arg0) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.IFormComponent#getDisplayName()
	 */
	public String getDisplayName() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.IFormComponent#getClientId()
	 */
	public String getClientId() {
		// TODO Auto-generated method stub
		return null;
	}

}


===========================================================================

Authorize.jwc 

<?xml version="1.0"?>
<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<component-specification
class="ca.itstrategic.tls.ptpip.ui.tapestry.components.Authorize">
  <inject property="dataSqueezer"
object="service:tapestry.data.DataSqueezer"/>
  <inject property="listenerInvoker"
object="infrastructure:listenerInvoker"/>
</component-specification>




-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Friday, June 09, 2006 5:49 PM
To: 'Tapestry users'; hugo.m.palma@gmail.com
Subject: RE: Tapestry/Acegi Integration...

I was actually thinking of a @Secured component that would conditionally
show its contents only if the user has the required permissions.

-----Original Message-----
From: Hugo Palma [mailto:hugo.m.palma@gmail.com] 
Sent: Friday, June 09, 2006 5:45 PM
To: Tapestry users
Subject: Re: Tapestry/Acegi Integration...

I was just thinking about something that would be really cool.
It's a common requirement in some applications that some ui elements are 
hidden/shown depending on user role. What i'm thinking is that 
tapestry-acegi could provide the same @Secured annotation for component 
classes but it would have a different behavior. Instead of simply 
checking authorization and returning an error it the user doesn't have 
access permissions, it would show the component if the user had the 
given role and hide it otherwise.

Would this be cool or what ? :o)

James Carman wrote:
> Form-based authentication is coming soon! :-)  It should be quite easy.
>
>   
>> Hi,
>> a smooth integration of ACEGI into Tapestry is really cool stuff. We
>> managed it by using
>> the internal org.acegisecurity.util.FilterToBeanProxy  and
>> FilterChainProxy for authentication
>> and partially for authorization (user /not logged in without role check)
>> within the web.xml.
>>
>> Does this mean that it would be possible to just configure the
>> filterChainProxy in spring and
>> inject this spring bean as a "tapestry filter" in front of Tapestry
>> servlet? Or am I completely
>> wrong? Unfortunately we don't use basic HTTP authentication but a form
>> based authentication
>> incobination with an internal SSO solution.
>> Gernot
>>
>> On Friday 09 June 2006 10:49, James Carman wrote:
>>     
>>> Gernot,
>>>
>>> I plan on making the different login mechanisms more "pluggable" soon.
>>> I've
>>> got an idea that will make it much easier (making Tapestry support
>>> servlet
>>> filters as ServletRequestServicerFilters so I don't have to write
>>> "adapter"
>>> subclasses).  Once I get everything running smoothly, I'll release it as
>>> a
>>> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
>>> need is HTTP basic authentication.
>>>
>>> James
>>>       
>> --
>> Gernot Stocker,
>> Institute for Genomics and Bioinformatics(IGB)
>> Petersgasse 14, 8010 Graz, Austria
>> Tel.: ++43 316 873 5345
>> http://genome.tugraz.at
>>
>>     
>
>
> James Carman, President
> Carman Consulting, Inc.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by Jonathan Barker <jo...@gmail.com>.
James,

I'm including the code for the AclAuthorize component.  Again, it is based
on the Acegi JSP taglib code, and the tapestry @If component, and requires
cleanup as before.  

Perhaps "@AclSecured" would be an appropriate given your current naming.

The application I developed most recently services a call center, as well as
the clients they service, who are part of the same franchise company.  As
such, there are some interesting security restrictions because it's seldom
an all-or-none situation.  The declarative security so easy in Acegi hasn't
really applied very well.

The combination of the Authorize and AclAuthorize (with a few custom
AclProvider implementations), has been great.  I use them to selectively
display links (including in menus), and show or hide information on a page
that should be available to one group, but not another.  Really cool stuff.

I had two basic reasons for using Spring. 1) Hibernate support via Hivemind
was a little immature when I started, and 2) I knew I would be using Acegi.
I'm looking forward to giving Tapernate a try now that it will be combining
solutions to my major problems.

On an unrelated note, I'm interested in Conversations.  Have you looked at
the Seam project at JBoss?

Jonathan  



==================================
//Copyright 2004, 2005, 2006 The Apache Software Foundation
//
// 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.* 
 /*  Created on Apr 7, 2006
 *
 *	$Id: $
 *
 *	
 */
/*
 * This class is an adaptation of the code developed by Ben Alex and
published 
 * under the Apache License, Version 2.0.
 * 
 */
package ca.itstrategic.tls.ptpip.ui.tapestry.components;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

import org.acegisecurity.Authentication;
import org.acegisecurity.acl.AclEntry;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acl.basic.BasicAclEntry;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import diaphragma.tapspr.XWebApplicationContextUtils;



import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.HiveMind;
import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IBinding;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.annotations.ComponentClass;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.services.DataSqueezer;
import org.apache.tapestry.web.WebContext;


/**
 * @author jabarker
* @version $Revision:  $
 */
@ComponentClass(allowBody=true , allowInformalParameters=true)
public abstract class AclAuthorize extends AbstractFormComponent {

	/**
	 * An implementation of {AbstractFormComponent} that allows its
	 * body through if some authorizations are granted to the request's
principal.
	 * 
	 * <P>
	 * Only works with permissions that are subclasses of {@link
	 * org.acegisecurity.acl.basic.BasicAclEntry}.
	 * </p>
	 * 
	 * <p>
	 * One or more comma separate integer permissions are specified via
the
	 * <code>hasPermission</code> attribute. The tag will include its
body if
	 * <b>any</b> of the integer permissions have been granted to the
current
	 * <code>Authentication</code> (obtained from the
<code>SecurityContextHolder</code>).
	 * </p>
	 * 
	 * <p>
	 * For this class to operate it must be able to access the
application context
	 * via the <code>WebApplicationContextUtils</code> and locate an
{@link
	 * AclManager}. Application contexts have no need to have more than
one
	 * <code>AclManager</code> (as a provider-based implementation can
be used so
	 * that it locates a provider that is authoritative for the given
domain
	 * object instance), so the first <code>AclManager</code> located
will be
	 * used.
	 * </p>
	 *
	 * @author Ben Alex
	 * @version $Id: AclTag.java,v 1.8 2005/11/17 00:56:29 benalex Exp $
	 */

    public final static String IF_VALUE_ATTRIBUTE =
"org.mb.tapestry.base.IfValue";

    @Parameter(required=true)
    public abstract void setDomainObject(Object domainObject);

    public abstract Object getDomainObject();

    @Parameter(required=true)
    public abstract String getHasPermission();
    public abstract void setHasPermission(String hasPermission);
    
    @Parameter(required=false)
    public abstract IBinding getConditionValueBinding();

    @Parameter(required=false)
    public abstract boolean getVolatile();

    @Parameter(required=false)
    public abstract String getElement();

    @Parameter(required=false)
    public abstract IActionListener getListener();

    private boolean _rendering = false;

    private boolean _conditionValue;

    //~ Static fields/initializers
=============================================

    protected static final Log logger =
LogFactory.getLog(AclAuthorize.class);

    //~ Methods
================================================================

    @InjectObject("service:tapestry.globals.WebContext")
    public abstract WebContext getWebContext();

    protected void renderComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
        boolean cycleRewinding = cycle.isRewinding();

        // form may be null if component is not located in a form
        IForm form = (IForm)
cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);

        // If the cycle is rewinding, but not this particular form,
        // then do nothing (don't even render the body).
        if (cycleRewinding && form != null && !form.isRewinding())
            return;

        // get the condition. work with a hidden field if necessary
        _conditionValue = evaluateCondition(cycle, form, cycleRewinding);
        _rendering = true;

        try
        {
            // call listener
            IActionListener listener = getListener();
            if (listener != null)
                listener.actionTriggered(this, cycle);

            // now render if condition is true
            if (_conditionValue)
            {
                String element = getElement();

                boolean render = !cycleRewinding &&
HiveMind.isNonBlank(element);

                if (render)
                {
                    writer.begin(element);
                    renderInformalParameters(writer, cycle);
                }

                renderBody(writer, cycle);

                if (render)
                    writer.end(element);
            }
        }
        finally
        {
            _rendering = false;
        }

        cycle.setAttribute(IF_VALUE_ATTRIBUTE, new
Boolean(_conditionValue));
    }

    protected boolean evaluateCondition(IRequestCycle cycle, IForm form,
boolean cycleRewinding)
    {
        boolean condition;

        if (form == null || getVolatile())
        {
            condition = checkPermission();
        }
        else
        {
            // we are in a form and we care -- load/store the condition in a
hidden field
            String name = form.getElementId(this);

            if (!cycleRewinding)
            {
                condition = checkPermission();
                writeValue(form, name, condition);
            }
            else
            {
                condition = readValue(cycle, name);
            }
        }

        // write condition value if parameter is bound
        IBinding conditionValueBinding = getConditionValueBinding();
        if (conditionValueBinding != null)
            conditionValueBinding.setObject(new Boolean(condition));

        return condition;
    }

    private void writeValue(IForm form, String name, boolean value)
    {
        String externalValue;

        Object booleanValue = new Boolean(value);
        try
        {
            externalValue = getDataSqueezer().squeeze(booleanValue);
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-value",
                    booleanValue), this, null, ex);
        }

        form.addHiddenValue(name, externalValue);
    }

    private boolean readValue(IRequestCycle cycle, String name)
    {
        String submittedValue = cycle.getParameter(name);

        try
        {
            Object valueObject =
getDataSqueezer().unsqueeze(submittedValue);
            if (!(valueObject instanceof Boolean))
                throw new ApplicationRuntimeException(Tapestry.format(
                        "If.invalid-condition-type",
                        submittedValue));

            return ((Boolean) valueObject).booleanValue();
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-string",
                    submittedValue), this, null, ex);
        }
    }

    public abstract DataSqueezer getDataSqueezer();

    public boolean isDisabled()
    {
        return false;
    }

    /**
     * Returns the value of the condition
     * 
     * @return the condition value
     */
    public boolean getConditionValue()
    {
        if (!_rendering)
            throw Tapestry.createRenderOnlyPropertyException(this,
"conditionValue");

        return _conditionValue;
    }

    // Do nothing in those methods, but make the JVM happy
    protected void renderFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    /**
     * For component can not take focus.
     */
    protected boolean getCanTakeFocus()
    {
        return false;
    }

    private boolean checkPermission(){
    		String hasPermission = getHasPermission();
    		
	        if ((null == hasPermission) || "".equals(hasPermission)) {
	            return false;
	        }

	        Integer[] requiredIntegers = null;

	        try {
	            requiredIntegers = parseIntegersString(hasPermission);
	        } catch (NumberFormatException nfe) {
	            throw new RuntimeException(nfe);
	        }
	        
	        Object domainObject = getDomainObject();

	        if (domainObject == null) {
	            if (logger.isDebugEnabled()) {
	                logger.debug(
	                    "domainObject resolved to null, so including tag
body");
	            }
	            return true;
	        }

	        if (SecurityContextHolder.getContext().getAuthentication()
== null) {
	            if (logger.isDebugEnabled()) {
	                logger.debug(
	                    "SecurityContextHolder did not return a non-null
Authentication object, so skipping tag body");
	            }

	            return false;
	        }

	        Authentication auth = SecurityContextHolder.getContext()
	
.getAuthentication();

	        ApplicationContext context = getContext();
	        Map beans = context.getBeansOfType(AclManager.class, false,
false);

	        if (beans.size() == 0) {
	            throw new RuntimeException(
	                "No AclManager would found the application context:
"
	                + context.toString());
	        }

	        String beanName = (String) beans.keySet().iterator().next();
	        AclManager aclManager = (AclManager)
context.getBean(beanName);

	        // Obtain aclEntrys applying to the current Authentication
object
	        AclEntry[] acls = aclManager.getAcls(domainObject, auth);

	        if (logger.isDebugEnabled()) {
	            logger.debug("Authentication: '" + auth + "' has: "
	                + ((acls == null) ? 0 : acls.length)
	                + " AclEntrys for domain object: '" + domainObject
	                + "' from AclManager: '" + aclManager.toString() +
"'");
	        }

	        if ((acls == null) || (acls.length == 0)) {
	            return false;
	        }

	        for (int i = 0; i < acls.length; i++) {
	            // Locate processable AclEntrys
	            if (acls[i] instanceof BasicAclEntry) {
	            	BasicAclEntry processableAcl = (BasicAclEntry)
acls[i];

	                // See if principal has any of the required
permissions
	                for (int y = 0; y < requiredIntegers.length; y++) {
	                    if (processableAcl.isPermitted(
	                            requiredIntegers[y].intValue())) {
	                        if (logger.isDebugEnabled()) {
	                            logger.debug(
	                                "Including tag body as found
permission: "
	                                + requiredIntegers[y] + " due to
AclEntry: '"
	                                + processableAcl + "'");
	                        }

	                        return true;
	                    }
	                }
	            }
	        }

	        if (logger.isDebugEnabled()) {
	            logger.debug("No permission, so skipping tag body");
	        }

	        return false;
	    }

	    /**
	     * Allows test cases to override where application context
obtained from.
	     *
	     * @param pageContext so the <code>ServletContext</code> can be
accessed as
	     *        required by Spring's
<code>WebApplicationContextUtils</code>
	     *
	     * @return the Spring application context (never
<code>null</code>)
	     */
	    protected ApplicationContext getContext(){
	    	return
XWebApplicationContextUtils.getRequiredWebApplicationContext(getWebContext()
);
	    }

	    @SuppressWarnings("unchecked")
		private Integer[] parseIntegersString(String integersString)
	        throws NumberFormatException {
	        final Set integers = new HashSet();
	        final StringTokenizer tokenizer;
	        tokenizer = new StringTokenizer(integersString, ",", false);

	        while (tokenizer.hasMoreTokens()) {
	            String integer = tokenizer.nextToken();
	            integers.add(new Integer(integer));
	        }

	        return (Integer[]) integers.toArray(new Integer[] {});
	    }

}


================================================






-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Sunday, June 11, 2006 8:00 PM
To: 'Tapestry users'
Subject: RE: Tapestry/Acegi Integration...

Sounds good!  I'll probably call mine Secured, since it will match up with
the @Secured annotation that we use in code.  But, I'll probably lean on
some of the work you've done here once I get a chance to read through it.

<snip>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
Sounds good!  I'll probably call mine Secured, since it will match up with
the @Secured annotation that we use in code.  But, I'll probably lean on
some of the work you've done here once I get a chance to read through it.


-----Original Message-----
From: Jonathan Barker [mailto:jonathan.theitguy@gmail.com] 
Sent: Saturday, June 10, 2006 1:03 AM
To: 'Tapestry users'
Subject: RE: Tapestry/Acegi Integration...

Hi,

I've now been lurking for two years.  I finally had a project where I could
use Tapestry... and Hibernate, and Spring, and Acegi...  So many hills to
climb...

Anyway, I put together an @Authorize component combining code from the
Tapestry @If component and the JSP taglib from Acegi.

As it stands, it behaves exactly as an @If, except that it takes
comma-separated lists of roles as parameters like the Acegi Auuthorize tag.
I also use @Else along with it - it hardly seemed necessary to come up with
a different AuthorizeElse component  I'm using it in production, and it
works beautifully.  I have also put together an AclAuthorize component for
instance-based security, if you are interested.

I would be happy to see this component included in a properly maintained
library under the Apache license.  At this point, I haven't even had a
chance to extract it into a library of my own or get back to it to clean up
the code and comments which include remnants of the taglib.

I haven't tried tapernate yet so I don't know if this is a simple drop-in.

  
Best regards,

Jonathan Barker


Code:
=====================================================

package ca.itstrategic.tls.ptpip.ui.tapestry.components;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.HiveMind;
import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IBinding;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.annotations.ComponentClass;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.services.DataSqueezer;
import org.apache.tapestry.web.WebContext;
import org.apache.tapestry.web.WebRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;

import diaphragma.tapspr.XWebApplicationContextUtils;

/**
 * @author jabarker
 * @version $Revision:  $
 */
@ComponentClass(allowInformalParameters=true, allowBody=true)
public abstract class Authorize extends AbstractFormComponent {

	@Parameter(required=false)
	public abstract String getIfAllGranted();
	@Parameter(required=false)
	public abstract String getIfAnyGranted();
	@Parameter(required=false)
	public abstract String getIfNotGranted();
	
	

	/**
	 * An implementation of {BaseComponent} that allows its
	 * body through if some authorizations are granted to the request's
principal.
	 * 
	 * <P>
	 * Only works with permissions that are subclasses of {@link
	 * org.acegisecurity.acl.basic.BasicAclEntry}.
	 * </p>
	 * 
	 * <p>
	 * One or more comma separate integer permissions are specified via
the
	 * <code>hasPermission</code> attribute. The tag will include its
body if
	 * <b>any</b> of the integer permissions have been granted to the
current
	 * <code>Authentication</code> (obtained from the
<code>SecurityContextHolder</code>).
	 * </p>
	 * 
	 * <p>
	 * For this class to operate it must be able to access the
application context
	 * via the <code>WebApplicationContextUtils</code> and locate an
{@link
	 * AclManager}. Application contexts have no need to have more than
one
	 * <code>AclManager</code> (as a provider-based implementation can
be used so
	 * that it locates a provider that is authoritative for the given
domain
	 * object instance), so the first <code>AclManager</code> located
will be
	 * used.
	 * </p>
	 *
	 * @author Ben Alex
	 */

    public final static String IF_VALUE_ATTRIBUTE =
"org.mb.tapestry.base.IfValue";

    @Parameter(required=false)
    public abstract IBinding getConditionValueBinding();

    @Parameter(required=false)
    public abstract boolean getVolatile();

    @Parameter(required=false)
    public abstract String getElement();

    @Parameter(required=false)
    public abstract IActionListener getListener();

    private boolean _rendering = false;

    private boolean _conditionValue;

    //~ Static fields/initializers
=============================================

    protected static final Log logger =
LogFactory.getLog(AclAuthorize.class);

    //~ Methods
================================================================

    @InjectObject("service:tapestry.globals.WebContext")
    public abstract WebContext getWebContext();

    @InjectObject("service:tapestry.globals.WebRequest")
    public abstract WebRequest getWebRequest();
    
    protected void renderComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
        boolean cycleRewinding = cycle.isRewinding();

        // form may be null if component is not located in a form
        IForm form = (IForm)
cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);

        // If the cycle is rewinding, but not this particular form,
        // then do nothing (don't even render the body).
        if (cycleRewinding && form != null && !form.isRewinding())
            return;

        // get the condition. work with a hidden field if necessary
        _conditionValue = evaluateCondition(cycle, form, cycleRewinding);
        _rendering = true;

        try
        {
            // call listener
            IActionListener listener = getListener();
            if (listener != null)
                listener.actionTriggered(this, cycle);

            // now render if condition is true
            if (_conditionValue)
            {
                String element = getElement();

                boolean render = !cycleRewinding &&
HiveMind.isNonBlank(element);

                if (render)
                {
                    writer.begin(element);
                    renderInformalParameters(writer, cycle);
                }

                renderBody(writer, cycle);

                if (render)
                    writer.end(element);
            }
        }
        finally
        {
            _rendering = false;
        }

        cycle.setAttribute(IF_VALUE_ATTRIBUTE, new
Boolean(_conditionValue));
    }

    protected boolean evaluateCondition(IRequestCycle cycle, IForm form,
boolean cycleRewinding)
    {
        boolean condition;

        if (form == null || getVolatile())
        {
            condition = checkPermission();
        }
        else
        {
            // we are in a form and we care -- load/store the condition in a
hidden field
            String name = form.getElementId(this);

            if (!cycleRewinding)
            {
                condition = checkPermission();
                writeValue(form, name, condition);
            }
            else
            {
                condition = readValue(cycle, name);
            }
        }

        // write condition value if parameter is bound
        IBinding conditionValueBinding = getConditionValueBinding();
        if (conditionValueBinding != null)
            conditionValueBinding.setObject(new Boolean(condition));

        return condition;
    }

    private void writeValue(IForm form, String name, boolean value)
    {
        String externalValue;

        Object booleanValue = new Boolean(value);
        try
        {
            externalValue = getDataSqueezer().squeeze(booleanValue);
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-value",
                    booleanValue), this, null, ex);
        }

        form.addHiddenValue(name, externalValue);
    }

    private boolean readValue(IRequestCycle cycle, String name)
    {
        String submittedValue = cycle.getParameter(name);

        try
        {
            Object valueObject =
getDataSqueezer().unsqueeze(submittedValue);
            if (!(valueObject instanceof Boolean))
                throw new ApplicationRuntimeException(Tapestry.format(
                        "If.invalid-condition-type",
                        submittedValue));

            return ((Boolean) valueObject).booleanValue();
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-string",
                    submittedValue), this, null, ex);
        }
    }

    public abstract DataSqueezer getDataSqueezer();

    public boolean isDisabled()
    {
        return false;
    }

    /**
     * Returns the value of the condition
     * 
     * @return the condition value
     */
    public boolean getConditionValue()
    {
        if (!_rendering)
            throw Tapestry.createRenderOnlyPropertyException(this,
"conditionValue");

        return _conditionValue;
    }

    // Do nothing in those methods, but make the JVM happy
    protected void renderFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    /**
     * For component can not take focus.
     */
    protected boolean getCanTakeFocus()
    {
        return false;
    }

    @SuppressWarnings("unchecked")
	private boolean checkPermission(){
    		String ifAllGranted = getIfAllGranted();
    		String ifAnyGranted = getIfAnyGranted();
    		String ifNotGranted = getIfNotGranted();
    		
            if (((null == ifAllGranted) || "".equals(ifAllGranted))
                    && ((null == ifAnyGranted) || "".equals(ifAnyGranted))
                    && ((null == ifNotGranted) || "".equals(ifNotGranted)))
{
                    return false;
                }
            

            final Collection granted = getPrincipalAuthorities();

            if ((null != ifNotGranted) && !"".equals(ifNotGranted)) {
                Set grantedCopy = retainAll(granted,
                        parseAuthoritiesString(ifNotGranted));

                if (!grantedCopy.isEmpty()) {
                    return false;
                }
            }

            if ((null != ifAllGranted) && !"".equals(ifAllGranted)) {
                if
(!granted.containsAll(parseAuthoritiesString(ifAllGranted))) {
                    return false;
                }
            }

            if ((null != ifAnyGranted) && !"".equals(ifAnyGranted)) {
                Set grantedCopy = retainAll(granted,
                        parseAuthoritiesString(ifAnyGranted));

                if (grantedCopy.isEmpty()) {
                    return false;
                }
            }

            return true;

            
            
//=========    		
	    }

	    /**
	     * Allows test cases to override where application context
obtained from.
	     *
	     * @param pageContext so the <code>ServletContext</code> can be
accessed as
	     *        required by Spring's
<code>WebApplicationContextUtils</code>
	     *
	     * @return the Spring application context (never
<code>null</code>)
	     */
	    protected ApplicationContext getContext(){
	    	return
XWebApplicationContextUtils.getRequiredWebApplicationContext(getWebContext()
);
	    }

	    private Collection getPrincipalAuthorities() {
//	    	SecurityContext sc = (SecurityContext)
getWebRequest().getSession(false).getAttribute(org.acegisecurity.context.Htt
pSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
	    	Authentication currentUser = null;
//			if(sc != null)
//			    currentUser = sc.getAuthentication();
	        currentUser =
SecurityContextHolder.getContext().getAuthentication();

	        if (null == currentUser) {
	            return Collections.EMPTY_LIST;
	        }

	        if ((null == currentUser.getAuthorities())
	            || (currentUser.getAuthorities().length < 1)) {
	            return Collections.EMPTY_LIST;
	        }

	        Collection granted =
Arrays.asList(currentUser.getAuthorities());
	        return granted;
	    }

	    @SuppressWarnings("unchecked")
		private Set authoritiesToRoles(Collection c) {
	        Set target = new HashSet();

	        for (Iterator iterator = c.iterator(); iterator.hasNext();)
{
	            GrantedAuthority authority = (GrantedAuthority)
iterator.next();

	            if (null == authority.getAuthority()) {
	                throw new IllegalArgumentException(
	                    "Cannot process GrantedAuthority objects which
return null from getAuthority() - attempting to process "
	                    + authority.toString());
	            }

	            target.add(authority.getAuthority());
	        }

	        return target;
	    }

	    @SuppressWarnings("unchecked")
		private Set parseAuthoritiesString(String
authorizationsString) {
	        final Set requiredAuthorities = new HashSet();
	        final String[] authorities = StringUtils
	            .commaDelimitedListToStringArray(authorizationsString);

	        for (int i = 0; i < authorities.length; i++) {
	            String authority = authorities[i];

	         // Remove the role's whitespace characters without
depending on JDK 1.4+ 
	         // Includes space, tab, new line, carriage return and form
feed. 
	         String role = StringUtils.replace(authority, " ", ""); 
	         role = StringUtils.replace(role, "\t", ""); 
	         role = StringUtils.replace(role, "\r", ""); 
	         role = StringUtils.replace(role, "\n", ""); 
	         role = StringUtils.replace(role, "\f", ""); 

	         requiredAuthorities.add(new GrantedAuthorityImpl(role));
	        }

	        return requiredAuthorities;
	    }

	    /**
	     * Find the common authorities between the current
authentication's {@link
	     * GrantedAuthority} and the ones that have been specified in
the tag's
	     * ifAny, ifNot or ifAllGranted attributes.
	     * 
	     * <p>
	     * We need to manually iterate over both collections, because
the granted
	     * authorities might not implement {@link Object#equals(Object)}
and
	     * {@link Object#hashCode()} in the same way as {@link
	     * GrantedAuthorityImpl}, thereby invalidating {@link
	     * Collection#retainAll(java.util.Collection)} results.
	     * </p>
	     * 
	     * <p>
	     * <strong>CAVEAT</strong>:  This method <strong>will
not</strong> work if
	     * the granted authorities returns a <code>null</code> string as
the
	     * return value of {@link
	     * org.acegisecurity.GrantedAuthority#getAuthority()}.
	     * </p>
	     * 
	     * <p>
	     * Reported by rawdave, on Fri Feb 04, 2005 2:11 pm in the Acegi
Security
	     * System for Spring forums.
	     * </p>
	     *
	     * @param granted The authorities granted by the authentication.
May be any
	     *        implementation of {@link GrantedAuthority} that does
	     *        <strong>not</strong> return <code>null</code> from
{@link
	     *        org.acegisecurity.GrantedAuthority#getAuthority()}.
	     * @param required A {@link Set} of {@link
GrantedAuthorityImpl}s that have
	     *        been built using ifAny, ifAll or ifNotGranted.
	     *
	     * @return A set containing only the common authorities between
	     *         <var>granted</var> and <var>required</var>.
	     *
	     * @see <a
	     *
href="http://forum.springframework.org/viewtopic.php?t=3367">authz:authorize
	     *      ifNotGranted not behaving as expected</a>
	     */
	    @SuppressWarnings("unchecked")
		private Set retainAll(final Collection granted, final Set
required) {
	        Set grantedRoles = authoritiesToRoles(granted);
	        Set requiredRoles = authoritiesToRoles(required);
	        grantedRoles.retainAll(requiredRoles);

	        return rolesToAuthorities(grantedRoles, granted);
	    }

	    @SuppressWarnings("unchecked")
		private Set rolesToAuthorities(Set grantedRoles, Collection
granted) {
	        Set target = new HashSet();

	        for (Iterator iterator = grantedRoles.iterator();
iterator.hasNext();) {
	            String role = (String) iterator.next();

	            for (Iterator grantedIterator = granted.iterator();
	                grantedIterator.hasNext();) {
	                GrantedAuthority authority = (GrantedAuthority)
grantedIterator
	                    .next();

	                if (authority.getAuthority().equals(role)) {
	                    target.add(authority);

	                    break;
	                }
	            }
	        }

	        return target;
	    }

//========================================================	
	/**
	 * 
	 */
	public Authorize() {
		super();
		// TODO Auto-generated constructor stub
	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.AbstractFormComponent#getForm()
	 */
	@Override
	public IForm getForm() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see
org.apache.tapestry.form.AbstractFormComponent#setForm(org.apache.tapestry.I
Form)
	 */
	@Override
	public void setForm(IForm arg0) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.IFormComponent#getDisplayName()
	 */
	public String getDisplayName() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.IFormComponent#getClientId()
	 */
	public String getClientId() {
		// TODO Auto-generated method stub
		return null;
	}

}


===========================================================================

Authorize.jwc 

<?xml version="1.0"?>
<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<component-specification
class="ca.itstrategic.tls.ptpip.ui.tapestry.components.Authorize">
  <inject property="dataSqueezer"
object="service:tapestry.data.DataSqueezer"/>
  <inject property="listenerInvoker"
object="infrastructure:listenerInvoker"/>
</component-specification>




-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Friday, June 09, 2006 5:49 PM
To: 'Tapestry users'; hugo.m.palma@gmail.com
Subject: RE: Tapestry/Acegi Integration...

I was actually thinking of a @Secured component that would conditionally
show its contents only if the user has the required permissions.

-----Original Message-----
From: Hugo Palma [mailto:hugo.m.palma@gmail.com] 
Sent: Friday, June 09, 2006 5:45 PM
To: Tapestry users
Subject: Re: Tapestry/Acegi Integration...

I was just thinking about something that would be really cool.
It's a common requirement in some applications that some ui elements are 
hidden/shown depending on user role. What i'm thinking is that 
tapestry-acegi could provide the same @Secured annotation for component 
classes but it would have a different behavior. Instead of simply 
checking authorization and returning an error it the user doesn't have 
access permissions, it would show the component if the user had the 
given role and hide it otherwise.

Would this be cool or what ? :o)

James Carman wrote:
> Form-based authentication is coming soon! :-)  It should be quite easy.
>
>   
>> Hi,
>> a smooth integration of ACEGI into Tapestry is really cool stuff. We
>> managed it by using
>> the internal org.acegisecurity.util.FilterToBeanProxy  and
>> FilterChainProxy for authentication
>> and partially for authorization (user /not logged in without role check)
>> within the web.xml.
>>
>> Does this mean that it would be possible to just configure the
>> filterChainProxy in spring and
>> inject this spring bean as a "tapestry filter" in front of Tapestry
>> servlet? Or am I completely
>> wrong? Unfortunately we don't use basic HTTP authentication but a form
>> based authentication
>> incobination with an internal SSO solution.
>> Gernot
>>
>> On Friday 09 June 2006 10:49, James Carman wrote:
>>     
>>> Gernot,
>>>
>>> I plan on making the different login mechanisms more "pluggable" soon.
>>> I've
>>> got an idea that will make it much easier (making Tapestry support
>>> servlet
>>> filters as ServletRequestServicerFilters so I don't have to write
>>> "adapter"
>>> subclasses).  Once I get everything running smoothly, I'll release it as
>>> a
>>> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
>>> need is HTTP basic authentication.
>>>
>>> James
>>>       
>> --
>> Gernot Stocker,
>> Institute for Genomics and Bioinformatics(IGB)
>> Petersgasse 14, 8010 Graz, Austria
>> Tel.: ++43 316 873 5345
>> http://genome.tugraz.at
>>
>>     
>
>
> James Carman, President
> Carman Consulting, Inc.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by Jonathan Barker <jo...@gmail.com>.
Hi,

I've now been lurking for two years.  I finally had a project where I could
use Tapestry... and Hibernate, and Spring, and Acegi...  So many hills to
climb...

Anyway, I put together an @Authorize component combining code from the
Tapestry @If component and the JSP taglib from Acegi.

As it stands, it behaves exactly as an @If, except that it takes
comma-separated lists of roles as parameters like the Acegi Auuthorize tag.
I also use @Else along with it - it hardly seemed necessary to come up with
a different AuthorizeElse component  I'm using it in production, and it
works beautifully.  I have also put together an AclAuthorize component for
instance-based security, if you are interested.

I would be happy to see this component included in a properly maintained
library under the Apache license.  At this point, I haven't even had a
chance to extract it into a library of my own or get back to it to clean up
the code and comments which include remnants of the taglib.

I haven't tried tapernate yet so I don't know if this is a simple drop-in.

  
Best regards,

Jonathan Barker


Code:
=====================================================

package ca.itstrategic.tls.ptpip.ui.tapestry.components;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.HiveMind;
import org.apache.tapestry.IActionListener;
import org.apache.tapestry.IBinding;
import org.apache.tapestry.IForm;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.TapestryUtils;
import org.apache.tapestry.annotations.ComponentClass;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Parameter;
import org.apache.tapestry.form.AbstractFormComponent;
import org.apache.tapestry.services.DataSqueezer;
import org.apache.tapestry.web.WebContext;
import org.apache.tapestry.web.WebRequest;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;

import diaphragma.tapspr.XWebApplicationContextUtils;

/**
 * @author jabarker
 * @version $Revision:  $
 */
@ComponentClass(allowInformalParameters=true, allowBody=true)
public abstract class Authorize extends AbstractFormComponent {

	@Parameter(required=false)
	public abstract String getIfAllGranted();
	@Parameter(required=false)
	public abstract String getIfAnyGranted();
	@Parameter(required=false)
	public abstract String getIfNotGranted();
	
	

	/**
	 * An implementation of {BaseComponent} that allows its
	 * body through if some authorizations are granted to the request's
principal.
	 * 
	 * <P>
	 * Only works with permissions that are subclasses of {@link
	 * org.acegisecurity.acl.basic.BasicAclEntry}.
	 * </p>
	 * 
	 * <p>
	 * One or more comma separate integer permissions are specified via
the
	 * <code>hasPermission</code> attribute. The tag will include its
body if
	 * <b>any</b> of the integer permissions have been granted to the
current
	 * <code>Authentication</code> (obtained from the
<code>SecurityContextHolder</code>).
	 * </p>
	 * 
	 * <p>
	 * For this class to operate it must be able to access the
application context
	 * via the <code>WebApplicationContextUtils</code> and locate an
{@link
	 * AclManager}. Application contexts have no need to have more than
one
	 * <code>AclManager</code> (as a provider-based implementation can
be used so
	 * that it locates a provider that is authoritative for the given
domain
	 * object instance), so the first <code>AclManager</code> located
will be
	 * used.
	 * </p>
	 *
	 * @author Ben Alex
	 */

    public final static String IF_VALUE_ATTRIBUTE =
"org.mb.tapestry.base.IfValue";

    @Parameter(required=false)
    public abstract IBinding getConditionValueBinding();

    @Parameter(required=false)
    public abstract boolean getVolatile();

    @Parameter(required=false)
    public abstract String getElement();

    @Parameter(required=false)
    public abstract IActionListener getListener();

    private boolean _rendering = false;

    private boolean _conditionValue;

    //~ Static fields/initializers
=============================================

    protected static final Log logger =
LogFactory.getLog(AclAuthorize.class);

    //~ Methods
================================================================

    @InjectObject("service:tapestry.globals.WebContext")
    public abstract WebContext getWebContext();

    @InjectObject("service:tapestry.globals.WebRequest")
    public abstract WebRequest getWebRequest();
    
    protected void renderComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
        boolean cycleRewinding = cycle.isRewinding();

        // form may be null if component is not located in a form
        IForm form = (IForm)
cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);

        // If the cycle is rewinding, but not this particular form,
        // then do nothing (don't even render the body).
        if (cycleRewinding && form != null && !form.isRewinding())
            return;

        // get the condition. work with a hidden field if necessary
        _conditionValue = evaluateCondition(cycle, form, cycleRewinding);
        _rendering = true;

        try
        {
            // call listener
            IActionListener listener = getListener();
            if (listener != null)
                listener.actionTriggered(this, cycle);

            // now render if condition is true
            if (_conditionValue)
            {
                String element = getElement();

                boolean render = !cycleRewinding &&
HiveMind.isNonBlank(element);

                if (render)
                {
                    writer.begin(element);
                    renderInformalParameters(writer, cycle);
                }

                renderBody(writer, cycle);

                if (render)
                    writer.end(element);
            }
        }
        finally
        {
            _rendering = false;
        }

        cycle.setAttribute(IF_VALUE_ATTRIBUTE, new
Boolean(_conditionValue));
    }

    protected boolean evaluateCondition(IRequestCycle cycle, IForm form,
boolean cycleRewinding)
    {
        boolean condition;

        if (form == null || getVolatile())
        {
            condition = checkPermission();
        }
        else
        {
            // we are in a form and we care -- load/store the condition in a
hidden field
            String name = form.getElementId(this);

            if (!cycleRewinding)
            {
                condition = checkPermission();
                writeValue(form, name, condition);
            }
            else
            {
                condition = readValue(cycle, name);
            }
        }

        // write condition value if parameter is bound
        IBinding conditionValueBinding = getConditionValueBinding();
        if (conditionValueBinding != null)
            conditionValueBinding.setObject(new Boolean(condition));

        return condition;
    }

    private void writeValue(IForm form, String name, boolean value)
    {
        String externalValue;

        Object booleanValue = new Boolean(value);
        try
        {
            externalValue = getDataSqueezer().squeeze(booleanValue);
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-value",
                    booleanValue), this, null, ex);
        }

        form.addHiddenValue(name, externalValue);
    }

    private boolean readValue(IRequestCycle cycle, String name)
    {
        String submittedValue = cycle.getParameter(name);

        try
        {
            Object valueObject =
getDataSqueezer().unsqueeze(submittedValue);
            if (!(valueObject instanceof Boolean))
                throw new ApplicationRuntimeException(Tapestry.format(
                        "If.invalid-condition-type",
                        submittedValue));

            return ((Boolean) valueObject).booleanValue();
        }
        catch (Exception ex)
        {
            throw new ApplicationRuntimeException(Tapestry.format(
                    "If.unable-to-convert-string",
                    submittedValue), this, null, ex);
        }
    }

    public abstract DataSqueezer getDataSqueezer();

    public boolean isDisabled()
    {
        return false;
    }

    /**
     * Returns the value of the condition
     * 
     * @return the condition value
     */
    public boolean getConditionValue()
    {
        if (!_rendering)
            throw Tapestry.createRenderOnlyPropertyException(this,
"conditionValue");

        return _conditionValue;
    }

    // Do nothing in those methods, but make the JVM happy
    protected void renderFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle
cycle)
    {
    }

    /**
     * For component can not take focus.
     */
    protected boolean getCanTakeFocus()
    {
        return false;
    }

    @SuppressWarnings("unchecked")
	private boolean checkPermission(){
    		String ifAllGranted = getIfAllGranted();
    		String ifAnyGranted = getIfAnyGranted();
    		String ifNotGranted = getIfNotGranted();
    		
            if (((null == ifAllGranted) || "".equals(ifAllGranted))
                    && ((null == ifAnyGranted) || "".equals(ifAnyGranted))
                    && ((null == ifNotGranted) || "".equals(ifNotGranted)))
{
                    return false;
                }
            

            final Collection granted = getPrincipalAuthorities();

            if ((null != ifNotGranted) && !"".equals(ifNotGranted)) {
                Set grantedCopy = retainAll(granted,
                        parseAuthoritiesString(ifNotGranted));

                if (!grantedCopy.isEmpty()) {
                    return false;
                }
            }

            if ((null != ifAllGranted) && !"".equals(ifAllGranted)) {
                if
(!granted.containsAll(parseAuthoritiesString(ifAllGranted))) {
                    return false;
                }
            }

            if ((null != ifAnyGranted) && !"".equals(ifAnyGranted)) {
                Set grantedCopy = retainAll(granted,
                        parseAuthoritiesString(ifAnyGranted));

                if (grantedCopy.isEmpty()) {
                    return false;
                }
            }

            return true;

            
            
//=========    		
	    }

	    /**
	     * Allows test cases to override where application context
obtained from.
	     *
	     * @param pageContext so the <code>ServletContext</code> can be
accessed as
	     *        required by Spring's
<code>WebApplicationContextUtils</code>
	     *
	     * @return the Spring application context (never
<code>null</code>)
	     */
	    protected ApplicationContext getContext(){
	    	return
XWebApplicationContextUtils.getRequiredWebApplicationContext(getWebContext()
);
	    }

	    private Collection getPrincipalAuthorities() {
//	    	SecurityContext sc = (SecurityContext)
getWebRequest().getSession(false).getAttribute(org.acegisecurity.context.Htt
pSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY);
	    	Authentication currentUser = null;
//			if(sc != null)
//			    currentUser = sc.getAuthentication();
	        currentUser =
SecurityContextHolder.getContext().getAuthentication();

	        if (null == currentUser) {
	            return Collections.EMPTY_LIST;
	        }

	        if ((null == currentUser.getAuthorities())
	            || (currentUser.getAuthorities().length < 1)) {
	            return Collections.EMPTY_LIST;
	        }

	        Collection granted =
Arrays.asList(currentUser.getAuthorities());
	        return granted;
	    }

	    @SuppressWarnings("unchecked")
		private Set authoritiesToRoles(Collection c) {
	        Set target = new HashSet();

	        for (Iterator iterator = c.iterator(); iterator.hasNext();)
{
	            GrantedAuthority authority = (GrantedAuthority)
iterator.next();

	            if (null == authority.getAuthority()) {
	                throw new IllegalArgumentException(
	                    "Cannot process GrantedAuthority objects which
return null from getAuthority() - attempting to process "
	                    + authority.toString());
	            }

	            target.add(authority.getAuthority());
	        }

	        return target;
	    }

	    @SuppressWarnings("unchecked")
		private Set parseAuthoritiesString(String
authorizationsString) {
	        final Set requiredAuthorities = new HashSet();
	        final String[] authorities = StringUtils
	            .commaDelimitedListToStringArray(authorizationsString);

	        for (int i = 0; i < authorities.length; i++) {
	            String authority = authorities[i];

	         // Remove the role's whitespace characters without
depending on JDK 1.4+ 
	         // Includes space, tab, new line, carriage return and form
feed. 
	         String role = StringUtils.replace(authority, " ", ""); 
	         role = StringUtils.replace(role, "\t", ""); 
	         role = StringUtils.replace(role, "\r", ""); 
	         role = StringUtils.replace(role, "\n", ""); 
	         role = StringUtils.replace(role, "\f", ""); 

	         requiredAuthorities.add(new GrantedAuthorityImpl(role));
	        }

	        return requiredAuthorities;
	    }

	    /**
	     * Find the common authorities between the current
authentication's {@link
	     * GrantedAuthority} and the ones that have been specified in
the tag's
	     * ifAny, ifNot or ifAllGranted attributes.
	     * 
	     * <p>
	     * We need to manually iterate over both collections, because
the granted
	     * authorities might not implement {@link Object#equals(Object)}
and
	     * {@link Object#hashCode()} in the same way as {@link
	     * GrantedAuthorityImpl}, thereby invalidating {@link
	     * Collection#retainAll(java.util.Collection)} results.
	     * </p>
	     * 
	     * <p>
	     * <strong>CAVEAT</strong>:  This method <strong>will
not</strong> work if
	     * the granted authorities returns a <code>null</code> string as
the
	     * return value of {@link
	     * org.acegisecurity.GrantedAuthority#getAuthority()}.
	     * </p>
	     * 
	     * <p>
	     * Reported by rawdave, on Fri Feb 04, 2005 2:11 pm in the Acegi
Security
	     * System for Spring forums.
	     * </p>
	     *
	     * @param granted The authorities granted by the authentication.
May be any
	     *        implementation of {@link GrantedAuthority} that does
	     *        <strong>not</strong> return <code>null</code> from
{@link
	     *        org.acegisecurity.GrantedAuthority#getAuthority()}.
	     * @param required A {@link Set} of {@link
GrantedAuthorityImpl}s that have
	     *        been built using ifAny, ifAll or ifNotGranted.
	     *
	     * @return A set containing only the common authorities between
	     *         <var>granted</var> and <var>required</var>.
	     *
	     * @see <a
	     *
href="http://forum.springframework.org/viewtopic.php?t=3367">authz:authorize
	     *      ifNotGranted not behaving as expected</a>
	     */
	    @SuppressWarnings("unchecked")
		private Set retainAll(final Collection granted, final Set
required) {
	        Set grantedRoles = authoritiesToRoles(granted);
	        Set requiredRoles = authoritiesToRoles(required);
	        grantedRoles.retainAll(requiredRoles);

	        return rolesToAuthorities(grantedRoles, granted);
	    }

	    @SuppressWarnings("unchecked")
		private Set rolesToAuthorities(Set grantedRoles, Collection
granted) {
	        Set target = new HashSet();

	        for (Iterator iterator = grantedRoles.iterator();
iterator.hasNext();) {
	            String role = (String) iterator.next();

	            for (Iterator grantedIterator = granted.iterator();
	                grantedIterator.hasNext();) {
	                GrantedAuthority authority = (GrantedAuthority)
grantedIterator
	                    .next();

	                if (authority.getAuthority().equals(role)) {
	                    target.add(authority);

	                    break;
	                }
	            }
	        }

	        return target;
	    }

//========================================================	
	/**
	 * 
	 */
	public Authorize() {
		super();
		// TODO Auto-generated constructor stub
	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.AbstractFormComponent#getForm()
	 */
	@Override
	public IForm getForm() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see
org.apache.tapestry.form.AbstractFormComponent#setForm(org.apache.tapestry.I
Form)
	 */
	@Override
	public void setForm(IForm arg0) {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.IFormComponent#getDisplayName()
	 */
	public String getDisplayName() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see org.apache.tapestry.form.IFormComponent#getClientId()
	 */
	public String getClientId() {
		// TODO Auto-generated method stub
		return null;
	}

}


===========================================================================

Authorize.jwc 

<?xml version="1.0"?>
<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd">

<component-specification
class="ca.itstrategic.tls.ptpip.ui.tapestry.components.Authorize">
  <inject property="dataSqueezer"
object="service:tapestry.data.DataSqueezer"/>
  <inject property="listenerInvoker"
object="infrastructure:listenerInvoker"/>
</component-specification>




-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Friday, June 09, 2006 5:49 PM
To: 'Tapestry users'; hugo.m.palma@gmail.com
Subject: RE: Tapestry/Acegi Integration...

I was actually thinking of a @Secured component that would conditionally
show its contents only if the user has the required permissions.

-----Original Message-----
From: Hugo Palma [mailto:hugo.m.palma@gmail.com] 
Sent: Friday, June 09, 2006 5:45 PM
To: Tapestry users
Subject: Re: Tapestry/Acegi Integration...

I was just thinking about something that would be really cool.
It's a common requirement in some applications that some ui elements are 
hidden/shown depending on user role. What i'm thinking is that 
tapestry-acegi could provide the same @Secured annotation for component 
classes but it would have a different behavior. Instead of simply 
checking authorization and returning an error it the user doesn't have 
access permissions, it would show the component if the user had the 
given role and hide it otherwise.

Would this be cool or what ? :o)

James Carman wrote:
> Form-based authentication is coming soon! :-)  It should be quite easy.
>
>   
>> Hi,
>> a smooth integration of ACEGI into Tapestry is really cool stuff. We
>> managed it by using
>> the internal org.acegisecurity.util.FilterToBeanProxy  and
>> FilterChainProxy for authentication
>> and partially for authorization (user /not logged in without role check)
>> within the web.xml.
>>
>> Does this mean that it would be possible to just configure the
>> filterChainProxy in spring and
>> inject this spring bean as a "tapestry filter" in front of Tapestry
>> servlet? Or am I completely
>> wrong? Unfortunately we don't use basic HTTP authentication but a form
>> based authentication
>> incobination with an internal SSO solution.
>> Gernot
>>
>> On Friday 09 June 2006 10:49, James Carman wrote:
>>     
>>> Gernot,
>>>
>>> I plan on making the different login mechanisms more "pluggable" soon.
>>> I've
>>> got an idea that will make it much easier (making Tapestry support
>>> servlet
>>> filters as ServletRequestServicerFilters so I don't have to write
>>> "adapter"
>>> subclasses).  Once I get everything running smoothly, I'll release it as
>>> a
>>> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
>>> need is HTTP basic authentication.
>>>
>>> James
>>>       
>> --
>> Gernot Stocker,
>> Institute for Genomics and Bioinformatics(IGB)
>> Petersgasse 14, 8010 Graz, Austria
>> Tel.: ++43 316 873 5345
>> http://genome.tugraz.at
>>
>>     
>
>
> James Carman, President
> Carman Consulting, Inc.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
I was actually thinking of a @Secured component that would conditionally
show its contents only if the user has the required permissions.

-----Original Message-----
From: Hugo Palma [mailto:hugo.m.palma@gmail.com] 
Sent: Friday, June 09, 2006 5:45 PM
To: Tapestry users
Subject: Re: Tapestry/Acegi Integration...

I was just thinking about something that would be really cool.
It's a common requirement in some applications that some ui elements are 
hidden/shown depending on user role. What i'm thinking is that 
tapestry-acegi could provide the same @Secured annotation for component 
classes but it would have a different behavior. Instead of simply 
checking authorization and returning an error it the user doesn't have 
access permissions, it would show the component if the user had the 
given role and hide it otherwise.

Would this be cool or what ? :o)

James Carman wrote:
> Form-based authentication is coming soon! :-)  It should be quite easy.
>
>   
>> Hi,
>> a smooth integration of ACEGI into Tapestry is really cool stuff. We
>> managed it by using
>> the internal org.acegisecurity.util.FilterToBeanProxy  and
>> FilterChainProxy for authentication
>> and partially for authorization (user /not logged in without role check)
>> within the web.xml.
>>
>> Does this mean that it would be possible to just configure the
>> filterChainProxy in spring and
>> inject this spring bean as a "tapestry filter" in front of Tapestry
>> servlet? Or am I completely
>> wrong? Unfortunately we don't use basic HTTP authentication but a form
>> based authentication
>> incobination with an internal SSO solution.
>> Gernot
>>
>> On Friday 09 June 2006 10:49, James Carman wrote:
>>     
>>> Gernot,
>>>
>>> I plan on making the different login mechanisms more "pluggable" soon.
>>> I've
>>> got an idea that will make it much easier (making Tapestry support
>>> servlet
>>> filters as ServletRequestServicerFilters so I don't have to write
>>> "adapter"
>>> subclasses).  Once I get everything running smoothly, I'll release it as
>>> a
>>> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
>>> need is HTTP basic authentication.
>>>
>>> James
>>>       
>> --
>> Gernot Stocker,
>> Institute for Genomics and Bioinformatics(IGB)
>> Petersgasse 14, 8010 Graz, Austria
>> Tel.: ++43 316 873 5345
>> http://genome.tugraz.at
>>
>>     
>
>
> James Carman, President
> Carman Consulting, Inc.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Tapestry/Acegi Integration...

Posted by Hugo Palma <hu...@gmail.com>.
I was just thinking about something that would be really cool.
It's a common requirement in some applications that some ui elements are 
hidden/shown depending on user role. What i'm thinking is that 
tapestry-acegi could provide the same @Secured annotation for component 
classes but it would have a different behavior. Instead of simply 
checking authorization and returning an error it the user doesn't have 
access permissions, it would show the component if the user had the 
given role and hide it otherwise.

Would this be cool or what ? :o)

James Carman wrote:
> Form-based authentication is coming soon! :-)  It should be quite easy.
>
>   
>> Hi,
>> a smooth integration of ACEGI into Tapestry is really cool stuff. We
>> managed it by using
>> the internal org.acegisecurity.util.FilterToBeanProxy  and
>> FilterChainProxy for authentication
>> and partially for authorization (user /not logged in without role check)
>> within the web.xml.
>>
>> Does this mean that it would be possible to just configure the
>> filterChainProxy in spring and
>> inject this spring bean as a "tapestry filter" in front of Tapestry
>> servlet? Or am I completely
>> wrong? Unfortunately we don't use basic HTTP authentication but a form
>> based authentication
>> incobination with an internal SSO solution.
>> Gernot
>>
>> On Friday 09 June 2006 10:49, James Carman wrote:
>>     
>>> Gernot,
>>>
>>> I plan on making the different login mechanisms more "pluggable" soon.
>>> I've
>>> got an idea that will make it much easier (making Tapestry support
>>> servlet
>>> filters as ServletRequestServicerFilters so I don't have to write
>>> "adapter"
>>> subclasses).  Once I get everything running smoothly, I'll release it as
>>> a
>>> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
>>> need is HTTP basic authentication.
>>>
>>> James
>>>       
>> --
>> Gernot Stocker,
>> Institute for Genomics and Bioinformatics(IGB)
>> Petersgasse 14, 8010 Graz, Austria
>> Tel.: ++43 316 873 5345
>> http://genome.tugraz.at
>>
>>     
>
>
> James Carman, President
> Carman Consulting, Inc.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>
>   

Re: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
Form-based authentication is coming soon! :-)  It should be quite easy.

> Hi,
> a smooth integration of ACEGI into Tapestry is really cool stuff. We
> managed it by using
> the internal org.acegisecurity.util.FilterToBeanProxy  and
> FilterChainProxy for authentication
> and partially for authorization (user /not logged in without role check)
> within the web.xml.
>
> Does this mean that it would be possible to just configure the
> filterChainProxy in spring and
> inject this spring bean as a "tapestry filter" in front of Tapestry
> servlet? Or am I completely
> wrong? Unfortunately we don't use basic HTTP authentication but a form
> based authentication
> incobination with an internal SSO solution.
> Gernot
>
> On Friday 09 June 2006 10:49, James Carman wrote:
>> Gernot,
>>
>> I plan on making the different login mechanisms more "pluggable" soon.
>> I've
>> got an idea that will make it much easier (making Tapestry support
>> servlet
>> filters as ServletRequestServicerFilters so I don't have to write
>> "adapter"
>> subclasses).  Once I get everything running smoothly, I'll release it as
>> a
>> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
>> need is HTTP basic authentication.
>>
>> James
> --
> Gernot Stocker,
> Institute for Genomics and Bioinformatics(IGB)
> Petersgasse 14, 8010 Graz, Austria
> Tel.: ++43 316 873 5345
> http://genome.tugraz.at
>


James Carman, President
Carman Consulting, Inc.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Tapestry/Acegi Integration...

Posted by Gernot Stocker <ge...@tugraz.at>.
Hi,
a smooth integration of ACEGI into Tapestry is really cool stuff. We managed it by using 
the internal org.acegisecurity.util.FilterToBeanProxy  and  FilterChainProxy for authentication 
and partially for authorization (user /not logged in without role check) within the web.xml.

Does this mean that it would be possible to just configure the filterChainProxy in spring and 
inject this spring bean as a "tapestry filter" in front of Tapestry servlet? Or am I completely 
wrong? Unfortunately we don't use basic HTTP authentication but a form based authentication 
incobination with an internal SSO solution.
Gernot

On Friday 09 June 2006 10:49, James Carman wrote:
> Gernot,
> 
> I plan on making the different login mechanisms more "pluggable" soon.  I've
> got an idea that will make it much easier (making Tapestry support servlet
> filters as ServletRequestServicerFilters so I don't have to write "adapter"
> subclasses).  Once I get everything running smoothly, I'll release it as a
> 1.0 (hopefully won't be too long).  You can use it now as-is, if all you
> need is HTTP basic authentication.
> 
> James
-- 
Gernot Stocker,
Institute for Genomics and Bioinformatics(IGB)
Petersgasse 14, 8010 Graz, Austria
Tel.: ++43 316 873 5345
http://genome.tugraz.at

RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
Gernot,

I plan on making the different login mechanisms more "pluggable" soon.  I've
got an idea that will make it much easier (making Tapestry support servlet
filters as ServletRequestServicerFilters so I don't have to write "adapter"
subclasses).  Once I get everything running smoothly, I'll release it as a
1.0 (hopefully won't be too long).  You can use it now as-is, if all you
need is HTTP basic authentication.

James

-----Original Message-----
From: Gernot Stocker [mailto:gernot.stocker@tugraz.at] 
Sent: Friday, June 09, 2006 4:11 AM
To: Tapestry users
Subject: Re: Tapestry/Acegi Integration...

Hi,
this sounds really great! Is there already a released jar file around which
can 
be just plugged in ;-) ?

I have a Tap/Spring webapplication in which ACEGI is already securing my 
service facade in the backend. A proper integration into the web ui would be

the next thing to do. Any plans for releasing the code may be as a beta?

Thanks,
    Gernot

On Friday 09 June 2006 01:34, James Carman wrote:
> All,
> 
> Now, Acegi secured methods are supported.  So, if you have a listener
method
> (taken from the tapernate example):
> 
> @Secured("ROLE_EDIT")
> public void editMessage( Message message )
> {
>  // Blah blah
> }
> 
> The tapernate-acegi module will perform a security check prior to
executing
> the editMessage() method to make sure that the currently authenticated
user
> has the role "ROLE_EDIT".  As before, you can place a @Secured annotation
on
> a page class and it will also be secured using a PageValidateListener
which
> checks for the appropriate role.  
> 
> Enjoy!
> 
> James
> 
> -----Original Message-----
> From: James Carman [mailto:james@carmanconsulting.com] 
> Sent: Thursday, June 08, 2006 10:26 AM
> To: 'Tapestry users'
> Subject: RE: Tapestry/Acegi Integration...
> 
> Oh, to login to the example application, you use tapernate/tapernate.
> 
> 
> -----Original Message-----
> From: James Carman [mailto:james@carmanconsulting.com] 
> Sent: Wednesday, June 07, 2006 10:38 PM
> To: 'Tapestry users'
> Subject: Tapestry/Acegi Integration...
> 
> All,
> 
> I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
> application now uses Acegi to secure the CreateMessage page (using a
> @Secured("ROLE_USER") annotation).  By no means is this the final version.
> I just wanted to get it in front of some folks to see what they thought.
> Enjoy!
> 
> James
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
> 
> 

-- 
Gernot Stocker,
Institute for Genomics and Bioinformatics(IGB)
Petersgasse 14, 8010 Graz, Austria
Tel.: ++43 316 873 5345
http://genome.tugraz.at



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: Tapestry/Acegi Integration...

Posted by Gernot Stocker <ge...@tugraz.at>.
Hi,
this sounds really great! Is there already a released jar file around which can 
be just plugged in ;-) ?

I have a Tap/Spring webapplication in which ACEGI is already securing my 
service facade in the backend. A proper integration into the web ui would be 
the next thing to do. Any plans for releasing the code may be as a beta?

Thanks,
    Gernot

On Friday 09 June 2006 01:34, James Carman wrote:
> All,
> 
> Now, Acegi secured methods are supported.  So, if you have a listener method
> (taken from the tapernate example):
> 
> @Secured("ROLE_EDIT")
> public void editMessage( Message message )
> {
>  // Blah blah
> }
> 
> The tapernate-acegi module will perform a security check prior to executing
> the editMessage() method to make sure that the currently authenticated user
> has the role "ROLE_EDIT".  As before, you can place a @Secured annotation on
> a page class and it will also be secured using a PageValidateListener which
> checks for the appropriate role.  
> 
> Enjoy!
> 
> James
> 
> -----Original Message-----
> From: James Carman [mailto:james@carmanconsulting.com] 
> Sent: Thursday, June 08, 2006 10:26 AM
> To: 'Tapestry users'
> Subject: RE: Tapestry/Acegi Integration...
> 
> Oh, to login to the example application, you use tapernate/tapernate.
> 
> 
> -----Original Message-----
> From: James Carman [mailto:james@carmanconsulting.com] 
> Sent: Wednesday, June 07, 2006 10:38 PM
> To: 'Tapestry users'
> Subject: Tapestry/Acegi Integration...
> 
> All,
> 
> I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
> application now uses Acegi to secure the CreateMessage page (using a
> @Secured("ROLE_USER") annotation).  By no means is this the final version.
> I just wanted to get it in front of some folks to see what they thought.
> Enjoy!
> 
> James
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
> 
> 

-- 
Gernot Stocker,
Institute for Genomics and Bioinformatics(IGB)
Petersgasse 14, 8010 Graz, Austria
Tel.: ++43 316 873 5345
http://genome.tugraz.at

RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
All,

Now, Acegi secured methods are supported.  So, if you have a listener method
(taken from the tapernate example):

@Secured("ROLE_EDIT")
public void editMessage( Message message )
{
 // Blah blah
}

The tapernate-acegi module will perform a security check prior to executing
the editMessage() method to make sure that the currently authenticated user
has the role "ROLE_EDIT".  As before, you can place a @Secured annotation on
a page class and it will also be secured using a PageValidateListener which
checks for the appropriate role.  

Enjoy!

James

-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Thursday, June 08, 2006 10:26 AM
To: 'Tapestry users'
Subject: RE: Tapestry/Acegi Integration...

Oh, to login to the example application, you use tapernate/tapernate.


-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Wednesday, June 07, 2006 10:38 PM
To: 'Tapestry users'
Subject: Tapestry/Acegi Integration...

All,

I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
application now uses Acegi to secure the CreateMessage page (using a
@Secured("ROLE_USER") annotation).  By no means is this the final version.
I just wanted to get it in front of some folks to see what they thought.
Enjoy!

James



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


RE: Tapestry/Acegi Integration...

Posted by James Carman <ja...@carmanconsulting.com>.
Oh, to login to the example application, you use tapernate/tapernate.


-----Original Message-----
From: James Carman [mailto:james@carmanconsulting.com] 
Sent: Wednesday, June 07, 2006 10:38 PM
To: 'Tapestry users'
Subject: Tapestry/Acegi Integration...

All,

I have taken a stab at Tapestry/Acegi integration.  The Tapernate example
application now uses Acegi to secure the CreateMessage page (using a
@Secured("ROLE_USER") annotation).  By no means is this the final version.
I just wanted to get it in front of some folks to see what they thought.
Enjoy!

James



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org