소스 검색

Added Java 5 Annotations version of Contacts sample (contacts-tiger).

Note: I have added a pre goal to add the source dir of  the original Contacts example.

I also added an exclude on the main project.properties for the attributes sample, as the Commons Attributes plugin causes issues with Java 5 source compilation.

The Annotations version will eventually replace the Commons Attributes approach, for now those users will need to manually build the attributes example.
Mark St. Godard 20 년 전
부모
커밋
9b898e84c4
36개의 변경된 파일2036개의 추가작업 그리고 0개의 파일을 삭제
  1. 1 0
      .classpath
  2. 1 0
      doc/xdocs/changes.xml
  3. 4 0
      project.properties
  4. 5 0
      project.xml
  5. 6 0
      samples/contacts-tiger/.cvsignore
  6. 57 0
      samples/contacts-tiger/maven.xml
  7. 26 0
      samples/contacts-tiger/project.properties
  8. 46 0
      samples/contacts-tiger/project.xml
  9. 205 0
      samples/contacts-tiger/src/main/java/sample/contact/annotation/ContactManagerBackend.java
  10. 37 0
      samples/contacts-tiger/src/main/resources/log4j.properties
  11. 2 0
      samples/contacts-tiger/src/main/resources/messages.properties
  12. 2 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/.cvsignore
  13. 163 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/applicationContext-common-authorization.xml
  14. 72 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/applicationContext-common-business.xml
  15. 87 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/contacts-servlet.xml
  16. 40 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/add.jsp
  17. 55 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/addPermission.jsp
  18. 39 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/adminPermission.jsp
  19. 18 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/deletePermission.jsp
  20. 13 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/deleted.jsp
  21. 51 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/hello.jsp
  22. 5 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/include.jsp
  23. 32 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/index.jsp
  24. 54 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/remoting-servlet.xml
  25. 311 0
      samples/contacts-tiger/src/main/webapp/common/WEB-INF/spring.tld
  26. 4 0
      samples/contacts-tiger/src/main/webapp/common/index.jsp
  27. 9 0
      samples/contacts-tiger/src/main/webapp/common/logoff.jsp
  28. 28 0
      samples/contacts-tiger/src/main/webapp/common/secure/debug.jsp
  29. 183 0
      samples/contacts-tiger/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml
  30. 184 0
      samples/contacts-tiger/src/main/webapp/filter/WEB-INF/applicationContext-annotations.xml
  31. 48 0
      samples/contacts-tiger/src/main/webapp/filter/WEB-INF/applicationContext-business.xml
  32. 107 0
      samples/contacts-tiger/src/main/webapp/filter/WEB-INF/web.xml
  33. 48 0
      samples/contacts-tiger/src/main/webapp/filter/acegilogin.jsp
  34. 5 0
      samples/contacts-tiger/src/main/webapp/filter/error.html
  35. 45 0
      samples/contacts-tiger/src/main/webapp/filter/exitUser.jsp
  36. 43 0
      samples/contacts-tiger/src/main/webapp/filter/switchUser.jsp

+ 1 - 0
.classpath

@@ -62,5 +62,6 @@
 	<classpathentry kind="src" path="samples/annotations/src/main/java"/>
 	<classpathentry kind="src" path="samples/annotations/src/main/resources"/>
 	<classpathentry kind="src" path="samples/annotations/src/test/java"/>
+	<classpathentry kind="src" path="samples/contacts-tiger/src/main/java"/>
 	<classpathentry kind="output" path="target/eclipseclasses"/>
 </classpath>

+ 1 - 0
doc/xdocs/changes.xml

@@ -26,6 +26,7 @@
   </properties>
   <body>
     <release version="0.9.0" date="In CVS">
+      <action dev="markstg" type="add">Added Contacts (Java 5) sample uses @Transactional and @Secured annotations</action>
       <action dev="markstg" type="add">SwitchUserProcessingFilter to provide user security context switching</action>
       <action dev="markstg" type="add">Java 1.5 annotation support</action>
       <action dev="benalex" type="update">BasicAuthenticationProcessingFilter no longer creates HttpSession via WebAuthenticationDetails call</action>

+ 4 - 0
project.properties

@@ -65,6 +65,10 @@ maven.license.licenseFile=${rootdir}/LICENSE.txt
 maven.multiproject.basedir=${rootdir}
 maven.multiproject.includes=core/project.xml,adapters/*/project.xml,samples/*/project.xml,domain/project.xml,core-tiger/project.xml
 
+# excluding the attributes project since the Commons Attributes plugin causes
+# problems with java 5 source code compilation 
+maven.multiproject.excludes=samples/attributes/project.xml
+
 # multichanges
 maven.multichanges.basedir=${maven.multiproject.basedir}
 maven.multichanges.includes=${maven.multiproject.includes}

+ 5 - 0
project.xml

@@ -102,6 +102,11 @@
       <id>robertsanders</id>
       <email>robertsanders at users.sourceforge.net</email>
     </developer>
+    <developer>
+      <name>Mark St.Godard</name>
+      <id>markstg</id>
+      <email>markstg at users.sourceforge.net</email>
+    </developer>
   </developers>
   <contributors>
     <contributor>

+ 6 - 0
samples/contacts-tiger/.cvsignore

@@ -0,0 +1,6 @@
+classes
+dist
+api
+build.properties
+temporary
+target

+ 57 - 0
samples/contacts-tiger/maven.xml

@@ -0,0 +1,57 @@
+<project
+   xmlns:j="jelly:core"
+   xmlns:ant="jelly:ant"
+   xmlns:artifact="artifact"
+   xmlns:maven="jelly:maven">
+
+    <preGoal name="java:compile">
+        <path id="additional.src.path">
+            <pathelement location="../contacts/src/main/java"/>
+        </path>
+        <maven:addPath id="maven.compile.src.set" refid="additional.src.path"/>
+    </preGoal> 
+	
+
+    <goal name="war">
+	    <echo>The "war" goal is deprecated. Use "multiwar:multiwar" instead.</echo>
+    </goal>
+    
+    <goal name="multiwar:multiwar">
+    	<!-- needed otherwise first custom artifact (cas) doesn't get built) -->
+        <attainGoal name="acegisecurity:war"/>
+
+        <!-- filter war -->
+        <j:set var="webapp" value="filter"/>
+        <attainGoal name="acegisecurity:war"/>
+
+	
+	<!-- delete generic artifact (we only want our three custom WARs) -->
+ 	    <ant:delete file="${maven.war.build.dir}/${pom.artifactId}.war"/>
+    </goal>
+    
+    <goal name="acegisecurity:war">
+        <maven:set plugin="maven-war-plugin"
+            property="maven.war.webapp.dir"
+            value="${maven.war.build.dir}/${pom.artifactId}-${webapp}"/>
+        <maven:set plugin="maven-war-plugin"
+            property="maven.war.final.name"
+            value="${pom.artifactId}-${webapp}.war"/>
+        <attainGoal name="war:war"/>
+    </goal>
+
+    <goal name="multiwar:install">
+        <attainGoal name="multiwar:multiwar"/>
+        <echo>multiproject:install doesn't install Contacts Samples WARs to local repo</echo>
+    </goal>
+
+    <postGoal name="war:war-resources">
+        <maven:get plugin="maven-war-plugin"
+            property="maven.war.webapp.dir"
+            var="maven.war.webapp.dir"/>
+        <ant:copy todir="${maven.war.webapp.dir}" preservelastmodified="true">
+            <ant:fileset dir="${maven.war.src}/../${webapp}"/>
+        </ant:copy>
+    </postGoal>
+
+
+</project>

+ 26 - 0
samples/contacts-tiger/project.properties

@@ -0,0 +1,26 @@
+# Ant properties for building the Contacts (Java 5) sample application.
+# $Id$
+
+name.filter=filter
+src.dir=src
+war.dir=war
+lib.dir=${basedir}/../../lib
+dist.lib.dir=${basedir}/../../dist
+build.dir=classes
+dist.dir=dist
+javadocs.dir=api
+jalopy.xml=${basedir}/../../jalopy.xml
+tmp.dir=temporary
+etc.dir=etc
+client.dir=client
+
+
+maven.war.src=${maven.src.dir}/main/webapp/common
+
+maven.multiproject.type=multiwar
+
+maven.xdoc.distributionType=war
+maven.xdoc.distributionUrl=http://acegisecurity.sourceforge.net/maven/acegisecurity/wars
+
+maven.compile.target=1.5
+maven.compile.source=1.5

+ 46 - 0
samples/contacts-tiger/project.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <extend>${basedir}/../project.xml</extend>
+  <pomVersion>3</pomVersion>
+  <artifactId>acegi-security-sample-contacts-tiger</artifactId>
+  <name>Acegi Security System for Spring - Contacts sample (Java 5)</name>
+  <groupId>acegisecurity</groupId>
+  <siteDirectory>/home/groups/a/ac/acegisecurity/htdocs/multiproject/acegi-security-sample-contacts-tiger</siteDirectory>
+  <repository>
+    <connection>scm:cvs:pserver:anonymous@cvs.sourceforge.net:/cvsroot/acegisecurity:acegisecurity</connection>
+    <developerConnection>scm:cvs:ext:${maven.username}@cvs.sourceforge.net:/cvsroot/acegisecurity:acegisecurity</developerConnection>
+    <url>http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/acegisecurity/acegisecurity/samples/contacts-tiger/</url>
+  </repository>
+  <dependencies>
+    <dependency>
+      <groupId>hessian</groupId>
+      <artifactId>hessian</artifactId>
+      <version>3.0.1</version>
+      <type>jar</type>
+      <url>http://www.caucho.com</url>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+    <dependency>
+      <groupId>burlap</groupId>
+      <artifactId>burlap</artifactId>
+      <version>2.1.7</version>
+      <type>jar</type>
+      <url>http://www.caucho.com</url>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+    <dependency>
+      <groupId>acegisecurity</groupId>
+      <artifactId>acegi-security-tiger</artifactId>
+      <version>0.9.0-SNAPSHOT</version>
+      <type>jar</type>
+      <properties>
+        <war.bundle>true</war.bundle>
+      </properties>
+    </dependency>
+  </dependencies>
+</project>
+

+ 205 - 0
samples/contacts-tiger/src/main/java/sample/contact/annotation/ContactManagerBackend.java

@@ -0,0 +1,205 @@
+/* Copyright 2004, 2005 Acegi Technology Pty Limited
+ *
+ * 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.
+ */
+
+package sample.contact.annotation;
+
+import java.util.List;
+import java.util.Random;
+
+import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.UserDetails;
+import net.sf.acegisecurity.acl.basic.AclObjectIdentity;
+import net.sf.acegisecurity.acl.basic.BasicAclExtendedDao;
+import net.sf.acegisecurity.acl.basic.NamedEntityObjectIdentity;
+import net.sf.acegisecurity.acl.basic.SimpleAclEntry;
+import net.sf.acegisecurity.annotation.Secured;
+import net.sf.acegisecurity.context.SecurityContextHolder;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.support.ApplicationObjectSupport;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import sample.contact.Contact;
+import sample.contact.ContactDao;
+import sample.contact.ContactManager;
+
+
+/**
+ * Concrete implementation of Java 5 Annotated {@link ContactManager}.
+ *
+ * @author Mark St.Godard
+ * @version $Id$
+ */
+@Transactional
+public class ContactManagerBackend extends ApplicationObjectSupport
+    implements ContactManager, InitializingBean {
+    //~ Instance fields ========================================================
+
+    private BasicAclExtendedDao basicAclExtendedDao;
+    private ContactDao contactDao;
+    private int counter = 100;
+
+    //~ Methods ================================================================
+
+    @Secured ({"ROLE_USER","AFTER_ACL_COLLECTION_READ"})
+    @Transactional(readOnly=true)
+    public List getAll() {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Returning all contacts");
+        }
+
+        return contactDao.findAll();
+    }
+
+    @Secured ({"ROLE_USER"})
+    @Transactional(readOnly=true)
+    public List getAllRecipients() {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Returning all recipients");
+        }
+
+        List list = contactDao.findAllPrincipals();
+        list.addAll(contactDao.findAllRoles());
+
+        return list;
+    }
+
+    public void setBasicAclExtendedDao(BasicAclExtendedDao basicAclExtendedDao) {
+        this.basicAclExtendedDao = basicAclExtendedDao;
+    }
+
+    public BasicAclExtendedDao getBasicAclExtendedDao() {
+        return basicAclExtendedDao;
+    }
+
+    @Secured ({"ROLE_USER","AFTER_ACL_READ"})
+    @Transactional(readOnly=true)
+    public Contact getById(Integer id) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Returning contact with id: " + id);
+        }
+
+        return contactDao.getById(id);
+    }
+
+    public void setContactDao(ContactDao contactDao) {
+        this.contactDao = contactDao;
+    }
+
+    public ContactDao getContactDao() {
+        return contactDao;
+    }
+
+    /**
+     * This is a public method.
+     *
+     * @return DOCUMENT ME!
+     */
+    public Contact getRandomContact() {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Returning random contact");
+        }
+
+        Random rnd = new Random();
+        List contacts = contactDao.findAll();
+        int getNumber = rnd.nextInt(contacts.size());
+
+        return (Contact) contacts.get(getNumber);
+    }
+
+    @Secured ({"ACL_CONTACT_ADMIN"})
+    public void addPermission(Contact contact, String recipient,
+        Integer permission) {
+        SimpleAclEntry simpleAclEntry = new SimpleAclEntry();
+        simpleAclEntry.setAclObjectIdentity(makeObjectIdentity(contact));
+        simpleAclEntry.setMask(permission.intValue());
+        simpleAclEntry.setRecipient(recipient);
+        basicAclExtendedDao.create(simpleAclEntry);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Added permission " + permission + " for recipient "
+                + recipient + " contact " + contact);
+        }
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        Assert.notNull(contactDao, "contactDao required");
+        Assert.notNull(basicAclExtendedDao, "basicAclExtendedDao required");
+    }
+
+    @Secured ({"ROLE_USER"})
+    public void create(Contact contact) {
+        // Create the Contact itself
+        contact.setId(new Integer(counter++));
+        contactDao.create(contact);
+
+        // Grant the current principal access to the contact 
+        addPermission(contact, getUsername(),
+            new Integer(SimpleAclEntry.ADMINISTRATION));
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Created contact " + contact
+                + " and granted admin permission to recipient " + getUsername());
+        }
+    }
+
+    @Secured ({"ACL_CONTACT_DELETE"})
+    public void delete(Contact contact) {
+        contactDao.delete(contact.getId());
+
+        // Delete the ACL information as well
+        basicAclExtendedDao.delete(makeObjectIdentity(contact));
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Deleted contact " + contact
+                + " including ACL permissions");
+        }
+    }
+
+    @Secured ({"ACL_CONTACT_ADMIN"})
+    public void deletePermission(Contact contact, String recipient) {
+        basicAclExtendedDao.delete(makeObjectIdentity(contact), recipient);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Deleted contact " + contact
+                + " ACL permissions for recipient " + recipient);
+        }
+    }
+
+    public void update(Contact contact) {
+        contactDao.update(contact);
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("Updated contact " + contact);
+        }
+    }
+
+    protected String getUsername() {
+        Authentication auth = SecurityContextHolder.getContext()
+                                                   .getAuthentication();
+
+        if (auth.getPrincipal() instanceof UserDetails) {
+            return ((UserDetails) auth.getPrincipal()).getUsername();
+        } else {
+            return auth.getPrincipal().toString();
+        }
+    }
+
+    private AclObjectIdentity makeObjectIdentity(Contact contact) {
+        return new NamedEntityObjectIdentity(contact.getClass().getName(),
+            contact.getId().toString());
+    }
+}

+ 37 - 0
samples/contacts-tiger/src/main/resources/log4j.properties

@@ -0,0 +1,37 @@
+# Global logging configuration
+log4j.rootLogger=WARN, stdout, fileout
+
+#log4j.logger.org.springframework.aop.framework.autoproxy=DEBUG, stdout, fileout
+#log4j.logger.org.springframework.aop.framework.autoproxy.metadata=DEBUG, stdout, fileout
+#log4j.logger.org.springframework.aop.framework.autoproxy.target=DEBUG, stdout, fileout
+#log4j.logger.org.springframework.transaction.interceptor=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.intercept=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.intercept.method=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.intercept.web=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.afterinvocation=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.acl=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.acl.basic=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.taglibs.authz=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.ui.basicauth=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.ui.rememberme=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.ui=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.afterinvocation=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.ui.rmi=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.ui.httpinvoker=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.util=DEBUG, stdout, fileout
+#log4j.logger.net.sf.acegisecurity.providers.dao=DEBUG, stdout, fileout
+log4j.logger.sample.contact=DEBUG, stdout, fileout
+
+# Console output...
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.conversionPattern=[%p,%c{1},%t] %m%n
+
+# Rolling log file output...
+log4j.appender.fileout=org.apache.log4j.RollingFileAppender
+log4j.appender.fileout.File=contacts.log
+#log4j.appender.fileout.File=${webapp.root}/WEB-INF/log4j.log
+log4j.appender.fileout.MaxFileSize=1024KB
+log4j.appender.fileout.MaxBackupIndex=1
+log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
+log4j.appender.fileout.layout.conversionPattern=%d{ABSOLUTE} %5p %c{1},%t:%L - %m%n

+ 2 - 0
samples/contacts-tiger/src/main/resources/messages.properties

@@ -0,0 +1,2 @@
+err.name.webContact.name=Name 3-50 characters is required.
+err.name.webContact.email=Email 3-50 characters is required.

+ 2 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/.cvsignore

@@ -0,0 +1,2 @@
+lib
+

+ 163 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/applicationContext-common-authorization.xml

@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Application context containing authentication beans.
+  -
+  - Used by all artifacts.
+  -
+  - $Id$
+  -->
+
+<beans>
+
+   <!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
+
+   <!-- ACL permission masks used by this application -->
+   <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
+      <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
+   </bean>
+   <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
+      <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
+   </bean>
+   <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
+      <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE</value></property>
+   </bean>
+
+
+   <!-- An access decision voter that reads ROLE_* configuration settings -->
+   <bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
+
+   <!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
+   <bean id="aclContactReadVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
+      <property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
+      <property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
+        </list>
+      </property>
+   </bean>
+
+   <!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
+   <bean id="aclContactDeleteVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
+      <property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
+      <property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/>
+        </list>
+      </property>
+   </bean>
+
+   <!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
+   <bean id="aclContactAdminVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
+      <property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
+      <property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+        </list>
+      </property>
+   </bean>
+
+   <!-- An access decision manager used by the business objects -->
+   <bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
+      <property name="allowIfAllAbstainDecisions"><value>false</value></property>
+      <property name="decisionVoters">
+         <list>
+            <ref local="roleVoter"/>
+            <ref local="aclContactReadVoter"/>
+            <ref local="aclContactDeleteVoter"/>
+            <ref local="aclContactAdminVoter"/>
+         </list>
+      </property>
+   </bean>
+
+   <!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
+
+   <bean id="aclManager" class="net.sf.acegisecurity.acl.AclProviderManager">
+      <property name="providers">
+         <list>
+            <ref local="basicAclProvider"/>
+         </list>
+      </property>
+   </bean>
+
+   <bean id="basicAclProvider" class="net.sf.acegisecurity.acl.basic.BasicAclProvider">
+      <property name="basicAclDao"><ref local="basicAclExtendedDao"/></property>
+   </bean>
+
+   <bean id="basicAclExtendedDao" class="net.sf.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
+      <property name="dataSource"><ref bean="dataSource"/></property>
+   </bean>
+
+   <!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
+
+   <bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
+      <property name="providers">
+         <list>
+            <ref local="afterAclRead"/>
+            <ref local="afterAclCollectionRead"/>
+         </list>
+      </property>
+   </bean>
+   
+   <!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
+   <bean id="afterAclCollectionRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
+        </list>
+      </property>
+   </bean>
+   
+   <!-- Processes AFTER_ACL_READ configuration settings -->
+   <bean id="afterAclRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
+        </list>
+      </property>
+   </bean>
+
+
+   <!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
+
+   <!-- getRandomContact() is public.
+
+    The create, getAll, getById etc have ROLE_USER to ensure user is
+    authenticated (all users hold ROLE_USER in this application).
+
+    The delete and update methods don't need a ROLE_USER as they will
+    ensure the user is authenticated via their ACL_CONTACT_DELETE or
+    ACL_CONTACT_READ attribute, which also ensures the user has permission
+    to the Contact presented as a method argument.
+    -->
+   <bean id="contactManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
+      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+      <property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
+      <property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
+      <property name="objectDefinitionSource">
+         <value>
+            sample.contact.ContactManager.create=ROLE_USER
+            sample.contact.ContactManager.getAllRecipients=ROLE_USER
+            sample.contact.ContactManager.getAll=ROLE_USER,AFTER_ACL_COLLECTION_READ
+            sample.contact.ContactManager.getById=ROLE_USER,AFTER_ACL_READ
+            sample.contact.ContactManager.delete=ACL_CONTACT_DELETE
+            sample.contact.ContactManager.deletePermission=ACL_CONTACT_ADMIN
+            sample.contact.ContactManager.addPermission=ACL_CONTACT_ADMIN
+         </value>
+      </property>
+   </bean>
+
+</beans>

+ 72 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/applicationContext-common-business.xml

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Application context containing business beans.
+  -
+  - Used by all artifacts.
+  -
+  - $Id$
+  -->
+
+<beans>
+
+    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+        <property name="driverClassName">
+            <value>org.hsqldb.jdbcDriver</value>
+        </property>
+        <property name="url">
+            <value>jdbc:hsqldb:mem:contacts</value>
+        </property>
+        <property name="username">
+            <value>sa</value>
+        </property>
+        <property name="password">
+            <value></value>
+        </property>
+    </bean>
+	
+	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+		<property name="dataSource"><ref local="dataSource"/></property>
+	</bean>
+	
+	<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
+    	<property name="transactionManager"><ref bean="transactionManager"/></property>
+		<property name="transactionAttributeSource">
+			<value>
+				sample.contact.ContactManager.create=PROPAGATION_REQUIRED
+				sample.contact.ContactManager.getAllRecipients=PROPAGATION_REQUIRED,readOnly
+				sample.contact.ContactManager.getAll=PROPAGATION_REQUIRED,readOnly
+				sample.contact.ContactManager.getById=PROPAGATION_REQUIRED,readOnly
+				sample.contact.ContactManager.delete=PROPAGATION_REQUIRED
+				sample.contact.ContactManager.deletePermission=PROPAGATION_REQUIRED
+				sample.contact.ContactManager.addPermission=PROPAGATION_REQUIRED
+			</value>
+		</property>
+	</bean>
+
+   <bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
+	   <property name="dataSource"><ref local="dataSource"/></property>
+   </bean>
+   
+   <bean id="contactDao" class="sample.contact.ContactDaoSpring">
+	   <property name="dataSource"><ref local="dataSource"/></property>
+   </bean>
+
+   <bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
+      <property name="proxyInterfaces"><value>sample.contact.ContactManager</value></property>
+      <property name="interceptorNames">
+         <list>
+            <idref local="transactionInterceptor"/>
+            <idref bean="contactManagerSecurity"/>
+            <idref local="contactManagerTarget"/>
+         </list>
+      </property>
+   </bean>
+
+   <bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
+	   <property name="contactDao"><ref local="contactDao"/></property>
+	   <property name="basicAclExtendedDao"><ref bean="basicAclExtendedDao"/></property>
+   </bean>
+
+</beans>

+ 87 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/contacts-servlet.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Application context definition for "contacts" DispatcherServlet.
+  -
+  - $Id$
+  -->
+
+<beans>
+
+	<!-- ========================== WEB DEFINITIONS ======================= -->
+
+	<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
+		<property name="basename"><value>messages</value></property>
+	</bean>
+
+    <bean id="publicIndexController" class="sample.contact.PublicIndexController">
+    	<property name="contactManager"><ref bean="contactManager"/></property>
+ 	</bean>
+
+    <bean id="secureIndexController" class="sample.contact.SecureIndexController">
+    	<property name="contactManager"><ref bean="contactManager"/></property>
+ 	</bean>
+
+    <bean id="secureDeleteController" class="sample.contact.DeleteController">
+    	<property name="contactManager"><ref bean="contactManager"/></property>
+ 	</bean>
+
+    <bean id="adminPermissionController" class="sample.contact.AdminPermissionController">
+    	<property name="contactManager"><ref bean="contactManager"/></property>
+    	<property name="aclManager"><ref bean="aclManager"/></property>
+ 	</bean>
+
+    <bean id="deletePermissionController" class="sample.contact.DeletePermissionController">
+    	<property name="contactManager"><ref bean="contactManager"/></property>
+    	<property name="aclManager"><ref bean="aclManager"/></property>
+ 	</bean>
+
+    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
+        <property name="mappings">
+            <props>
+                <prop key="/hello.htm">publicIndexController</prop>
+                <prop key="/secure/add.htm">secureAddForm</prop>
+                <prop key="/secure/index.htm">secureIndexController</prop>
+                <prop key="/secure/del.htm">secureDeleteController</prop>
+                <prop key="/secure/adminPermission.htm">adminPermissionController</prop>
+                <prop key="/secure/deletePermission.htm">deletePermissionController</prop>
+                <prop key="/secure/addPermission.htm">addPermissionForm</prop>
+			</props>
+        </property>
+    </bean>
+
+    <bean id="addValidator" class="sample.contact.WebContactValidator"/>
+    
+	<bean id="addPermissionValidator" class="sample.contact.AddPermissionValidator"/>
+
+    <bean id="secureAddForm" class="sample.contact.WebContactAddController">
+        <property name="sessionForm"><value>true</value></property>
+        <property name="commandName"><value>webContact</value></property>
+        <property name="commandClass"><value>sample.contact.WebContact</value></property>
+        <property name="validator"><ref bean="addValidator"/></property>
+        <property name="formView"><value>add</value></property>
+        <property name="successView"><value>index.htm</value></property>
+        <property name="contactManager">
+            <ref bean="contactManager"/>
+        </property>
+    </bean>
+
+    <bean id="addPermissionForm" class="sample.contact.AddPermissionController">
+        <property name="sessionForm"><value>true</value></property>
+        <property name="commandName"><value>addPermission</value></property>
+        <property name="commandClass"><value>sample.contact.AddPermission</value></property>
+        <property name="validator"><ref bean="addPermissionValidator"/></property>
+        <property name="formView"><value>addPermission</value></property>
+        <property name="successView"><value>index.htm</value></property>
+        <property name="contactManager">
+            <ref bean="contactManager"/>
+        </property>
+    </bean>
+
+	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
+		<property name="prefix"><value>/WEB-INF/jsp/</value></property>
+		<property name="suffix"><value>.jsp</value></property>
+	</bean>
+
+</beans>

+ 40 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/add.jsp

@@ -0,0 +1,40 @@
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+<html>
+<head><title>Add New Contact</title></head>
+<body>
+<h1>Add Contact</h1>
+<form method="post">
+  <table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
+    <tr>
+      <td alignment="right" width="20%">Name:</td>
+      <spring:bind path="webContact.name">
+        <td width="20%">
+          <input type="text" name="name" value="<c:out value="${status.value}"/>">
+        </td>
+        <td width="60%">
+          <font color="red"><c:out value="${status.errorMessage}"/></font>
+        </td>
+      </spring:bind>
+    </tr>
+    <tr>
+      <td alignment="right" width="20%">Email:</td>
+      <spring:bind path="webContact.email">
+        <td width="20%">
+          <input type="text" name="email" value="<c:out value="${status.value}"/>">
+        </td>
+        <td width="60%">
+          <font color="red"><c:out value="${status.errorMessage}"/></font>
+        </td>
+      </spring:bind>
+    </tr>
+  </table>
+  <br>
+  <spring:hasBindErrors name="webContact">
+    <b>Please fix all errors!</b>
+  </spring:hasBindErrors>
+  <br><br>
+  <input name="execute" type="submit" alignment="center" value="Execute">
+</form>
+<a href="<c:url value="../hello.htm"/>">Home</a>
+</body>
+</html>

+ 55 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/addPermission.jsp

@@ -0,0 +1,55 @@
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+<html>
+<head><title>Add Permission</title></head>
+<body>
+<h1>Add Permission</h1>
+<form method="post">
+  <table width="95%" bgcolor="f8f8ff" border="0" cellspacing="0" cellpadding="5">
+    <tr>
+      <td alignment="right" width="20%">Contact:</td>
+      <td width="60%"><c:out value="${addPermission.contact}"/></td>
+    </tr>
+    <tr>
+      <td alignment="right" width="20%">Recipient:</td>
+      <spring:bind path="addPermission.recipient">
+        <td width="20%">
+		    <select name="<c:out value="${status.expression}"/>">
+		      <c:forEach var="thisRecipient" items="${recipients}">
+		        <option <c:if test="${thisRecipient.key == status.value}">selected</c:if> value="<c:out value="${thisRecipient.key}"/>">
+		        <c:out value="${thisRecipient.value}"/></option>
+			    </c:forEach>
+		    </select>
+        </td>
+        <td width="60%">
+          <font color="red"><c:out value="${status.errorMessage}"/></font>
+        </td>
+      </spring:bind>
+    </tr>
+    <tr>
+      <td alignment="right" width="20%">Permission:</td>
+      <spring:bind path="addPermission.permission">
+        <td width="20%">
+		    <select name="<c:out value="${status.expression}"/>">
+		      <c:forEach var="thisPermission" items="${permissions}">
+		        <option <c:if test="${thisPermission.key == status.value}">selected</c:if> value="<c:out value="${thisPermission.key}"/>">
+		        <c:out value="${thisPermission.value}"/></option>
+			    </c:forEach>
+		    </select>
+        </td>
+        <td width="60%">
+          <font color="red"><c:out value="${status.errorMessage}"/></font>
+        </td>
+      </spring:bind>
+    </tr>
+  </table>
+  <br>
+  <spring:hasBindErrors name="webContact">
+    <b>Please fix all errors!</b>
+  </spring:hasBindErrors>
+  <br><br>
+  <input name="execute" type="submit" alignment="center" value="Execute">
+</form>
+<p>
+<A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${addPermission.contact.id}"/></c:url>">Admin Permission</A> <a href="<c:url value="index.htm"/>">Manage</a>
+</body>
+</html>

+ 39 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/adminPermission.jsp

@@ -0,0 +1,39 @@
+<%@ page import="net.sf.acegisecurity.acl.basic.SimpleAclEntry" %>
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+
+<html>
+<head><title>Administer Permissions</title></head>
+<body>
+<h1>Administer Permissions</h1>
+<P>
+<code>
+<c:out value="${model.contact}"/>
+</code>
+<P>
+<table cellpadding=3 border=0>
+<c:forEach var="acl" items="${model.acls}">
+  <c:if test="${acl.class.name eq 'net.sf.acegisecurity.acl.basic.SimpleAclEntry'}">
+    <tr>
+      <td>
+        <code>
+          <%
+            SimpleAclEntry simpleAcl = ((SimpleAclEntry) pageContext.getAttribute("acl"));
+            String permissionBlock = simpleAcl.printPermissionsBlock(); 
+          %>
+          <%= permissionBlock %>
+          [<c:out value="${acl.mask}"/>]
+          <c:out value="${acl.recipient}"/>
+        </code>
+      </td>
+      <td>
+      <!-- This application doesn't use ACL inheritance, so we can safely use
+           the model's contact and know it was directly assigned the ACL -->
+        <A HREF="<c:url value="deletePermission.htm"><c:param name="contactId" value="${model.contact.id}"/><c:param name="recipient" value="${acl.recipient}"/></c:url>">Del</A>
+      </td>
+    </tr>
+  </c:if>
+</c:forEach>
+</table>
+<p><a href="<c:url value="addPermission.htm"><c:param name="contactId" value="${model.contact.id}"/></c:url>">Add Permission</a>   <a href="<c:url value="index.htm"/>">Manage</a>
+</body>
+</html>

+ 18 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/deletePermission.jsp

@@ -0,0 +1,18 @@
+<%@ page import="net.sf.acegisecurity.acl.basic.SimpleAclEntry" %>
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+
+<html>
+<head><title>Permission Deleted</title></head>
+<body>
+<h1>Permission Deleted</h1>
+<P>
+<code>
+<c:out value="${model.contact}"/>
+</code>
+<P>
+<code>
+<c:out value="${model.recipient}"/>
+</code>
+<p><a href="<c:url value="index.htm"/>">Manage</a>
+</body>
+</html>

+ 13 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/deleted.jsp

@@ -0,0 +1,13 @@
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+
+<html>
+<head><title>Deletion completed</title></head>
+<body>
+<h1>Deleted</h1>
+<P>
+<code>
+<c:out value="${contact}"/>
+</code>
+<p><a href="<c:url value="index.htm"/>">Manage</a>
+</body>
+</html>

+ 51 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/hello.jsp

@@ -0,0 +1,51 @@
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+
+<html>
+<head><title>Contacts Security Demo</title></head>
+<body>
+<h1>Contacts Security Demo</h1>
+<P>Contacts demonstrates the following central Acegi Security capabilities:
+<ul>
+<li><b>Role-based security</b>. Each principal is a member of certain roles,
+    which are used to restrict access to certain secure objects.</li>
+<li><b>Domain object instance security</b>. The <code>Contact</code>, the
+    main domain object in the application, has an access control list (ACL)
+    that indicates who is allowed read, administer and delete the object.</li>
+<li><b>Method invocation security</b>. The <code>ContactManager</code> service
+   layer bean has a number of secured (protected) and public (unprotected)
+   methods.</li>
+<li><b>Web request security</b>. The <code>/secure</code> URI path is protected
+   by Acegi Security from principals not holding the 
+   <code>ROLE_USER</code> granted authority.</li>
+<li><b>Security unaware application objects</b>. None of the objects
+   are aware of the security being implemented by Acegi Security. *</li>
+<li><b>Security taglib usage</b>. All of the JSPs use Acegi Security's
+   taglib to evaluate security information. *</li>
+<li><b>Fully declarative security</b>. Every capability is configured in 
+   the application context using standard Acegi Security classes. *</li>
+<li><b>Database-sourced security data</b>. All of the user, role and ACL
+   information is obtained from an in-memory JDBC-compliant database.</li>
+<li><b>Integrated form-based and BASIC authentication</b>. Any BASIC
+   authentication header is detected and used for authentication. Normal
+   interactive form-based authentication is used by default.</li>
+<li><b>Remember-me services</b>. Acegi Security's pluggable remember-me
+   strategy is demonstrated, with a corresponding checkbox on the login form.</li>
+</ul>
+
+* As the application provides an "ACL Administration" use case, those
+classes are necessarily aware of security. But no business use cases are.
+
+<p>Please excuse the lack of look 'n' feel polish in this application.
+It is about security, after all! :-)
+
+<p>To demonstrate a public method on <code>ContactManager</code>,
+here's a random <code>Contact</code>:
+<p>
+<code>
+<c:out value="${contact}"/>
+</code>
+<p>Get started by clicking "Manage"...
+<p><A HREF="<c:url value="secure/index.htm"/>">Manage</a>
+<A HREF="<c:url value="secure/debug.jsp"/>">Debug</a>
+</body>
+</html>

+ 5 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/include.jsp

@@ -0,0 +1,5 @@
+<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
+<%@ taglib prefix="authz" uri="http://acegisecurity.sf.net/authz" %>
+
+<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>

+ 32 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/jsp/index.jsp

@@ -0,0 +1,32 @@
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+
+<html>
+<head><title>Your Contacts</title></head>
+<body>
+<h1><authz:authentication operation="principal"/>'s Contacts</h1>
+<P>
+<table cellpadding=3 border=0>
+<tr><td><b>id</b></td><td><b>Name</b></td><td><b>Email</b></td></tr>
+<c:forEach var="contact" items="${model.contacts}">
+  <tr>
+  <td>
+      <c:out value="${contact.id}"/>
+  </td>
+  <td>
+      <c:out value="${contact.name}"/>
+  </td>
+  <td>
+      <c:out value="${contact.email}"/>
+  </td>
+  <authz:acl domainObject="${contact}" hasPermission="16,1">
+    <td><A HREF="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</A></td>
+  </authz:acl>
+  <authz:acl domainObject="${contact}" hasPermission="1">
+    <td><A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</A></td>
+  </authz:acl>
+  </tr>
+</c:forEach>
+</table>
+<p><a href="<c:url value="add.htm"/>">Add</a>   <p><a href="<c:url value="../logoff.jsp"/>">Logoff</a> (also clears any remember-me cookie)
+</body>
+</html>

+ 54 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/remoting-servlet.xml

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Contacts web application
+  - $Id$
+  -->
+<beans>
+
+	<!-- RMI exporter for the ContactManager -->
+	<!-- This could just as easily have been in 
+		 applicationContext-common-business.xml, because it doesn't rely on
+		 DispatcherServlet or indeed any other HTTP services. It's in this
+		 application context simply for logical placement with other
+		 remoting exporters. -->
+	<!-- COMMENTED OUT BY DEFAULT TO AVOID CONFLICTS WITH APPLICATION SERVERS
+	<bean id="contactManager-rmi" class="org.springframework.remoting.rmi.RmiServiceExporter">
+		<property name="service"><ref bean="contactManager"/></property>
+		<property name="serviceInterface">
+			<value>sample.contact.ContactManager</value>
+		</property>
+		<property name="serviceName"><value>contactManager</value></property>
+		<property name="registryPort"><value>1099</value></property>
+	</bean>
+	-->
+
+	<!-- HTTP invoker exporter for the ContactManager -->
+	<!-- Spring's HTTP invoker uses Java serialization via HTTP  -->
+	<bean name="/ContactManager-httpinvoker" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
+		<property name="service"><ref bean="contactManager"/></property>
+		<property name="serviceInterface">
+			<value>sample.contact.ContactManager</value>
+		</property>
+	</bean>
+
+	<!-- Hessian exporter for the ContactManager -->
+	<!-- Hessian is a slim binary HTTP remoting protocol -->
+	<bean name="/ContactManager-hessian" class="org.springframework.remoting.caucho.HessianServiceExporter">
+		<property name="service"><ref bean="contactManager"/></property>
+		<property name="serviceInterface">
+			<value>sample.contact.ContactManager</value>
+		</property>
+	</bean>
+
+	<!-- Burlap exporter for the ContactManager -->
+	<!-- Burlap is a slim XML-based HTTP remoting protocol -->
+	<bean name="/ContactManager-burlap" class="org.springframework.remoting.caucho.BurlapServiceExporter">
+		<property name="service"><ref bean="contactManager"/></property>
+		<property name="serviceInterface">
+			<value>sample.contact.ContactManager</value>
+		</property>
+	</bean>
+
+</beans>

+ 311 - 0
samples/contacts-tiger/src/main/webapp/common/WEB-INF/spring.tld

@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
+
+<taglib>
+
+	<tlib-version>1.1.1</tlib-version>
+
+	<jsp-version>1.2</jsp-version>
+
+	<short-name>Spring</short-name>
+
+	<uri>http://www.springframework.org/tags</uri>
+
+	<description>Spring Framework JSP Tag Library. Authors: Rod Johnson, Juergen Hoeller</description>
+
+
+	<tag>
+
+		<name>htmlEscape</name>
+		<tag-class>org.springframework.web.servlet.tags.HtmlEscapeTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Sets default HTML escape value for the current page.
+			Overrides a "defaultHtmlEscape" context-param in web.xml, if any.
+		</description>
+
+		<attribute>
+			<name>defaultHtmlEscape</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>escapeBody</name>
+		<tag-class>org.springframework.web.servlet.tags.EscapeBodyTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Escapes its enclosed body content, applying HTML escaping and/or JavaScript escaping.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>message</name>
+		<tag-class>org.springframework.web.servlet.tags.MessageTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Retrieves the message with the given code, or text if code isn't resolvable.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>code</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>arguments</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>text</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>theme</name>
+		<tag-class>org.springframework.web.servlet.tags.ThemeTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Retrieves the theme message with the given code, or text if code isn't resolvable.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>code</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>arguments</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>text</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>javaScriptEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>hasBindErrors</name>
+		<tag-class>org.springframework.web.servlet.tags.BindErrorsTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Provides Errors instance in case of bind errors.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<variable>
+			<name-given>errors</name-given>
+			<variable-class>org.springframework.validation.Errors</variable-class>
+		</variable>
+
+		<attribute>
+			<name>name</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>nestedPath</name>
+		<tag-class>org.springframework.web.servlet.tags.NestedPathTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Sets a nested path to be used by the bind tag's path.
+		</description>
+
+		<variable>
+			<name-given>nestedPath</name-given>
+			<variable-class>java.lang.String</variable-class>
+		</variable>
+
+		<attribute>
+			<name>path</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>bind</name>
+		<tag-class>org.springframework.web.servlet.tags.BindTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Provides BindStatus object for the given bind path.
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<variable>
+			<name-given>status</name-given>
+			<variable-class>org.springframework.web.servlet.support.BindStatus</variable-class>
+		</variable>
+
+		<attribute>
+			<name>path</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>ignoreNestedPath</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+
+	<tag>
+
+		<name>transform</name>
+		<tag-class>org.springframework.web.servlet.tags.TransformTag</tag-class>
+		<body-content>JSP</body-content>
+
+		<description>
+			Provides transformation of variables to Strings, using an appropriate
+			custom PropertyEditor from BindTag (can only be used inside BindTag).
+			The HTML escaping flag participates in a page-wide or application-wide setting
+			(i.e. by HtmlEscapeTag or a "defaultHtmlEscape" context-param in web.xml).
+		</description>
+
+		<attribute>
+			<name>value</name>
+			<required>true</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>var</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>scope</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+		<attribute>
+			<name>htmlEscape</name>
+			<required>false</required>
+			<rtexprvalue>true</rtexprvalue>
+		</attribute>
+
+	</tag>
+
+</taglib>

+ 4 - 0
samples/contacts-tiger/src/main/webapp/common/index.jsp

@@ -0,0 +1,4 @@
+<%@ include file="/WEB-INF/jsp/include.jsp" %>
+
+<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
+<c:redirect url="/hello.htm"/>

+ 9 - 0
samples/contacts-tiger/src/main/webapp/common/logoff.jsp

@@ -0,0 +1,9 @@
+<%@ page import="javax.servlet.http.Cookie" %>
+<%@ page import="net.sf.acegisecurity.ui.rememberme.TokenBasedRememberMeServices" %>
+<%
+session.invalidate();
+Cookie terminate = new Cookie(TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY, null);
+terminate.setMaxAge(0);
+response.addCookie(terminate);
+response.sendRedirect("index.jsp");
+%>

+ 28 - 0
samples/contacts-tiger/src/main/webapp/common/secure/debug.jsp

@@ -0,0 +1,28 @@
+<%@ page import="net.sf.acegisecurity.context.SecurityContextHolder" %>
+<%@ page import="net.sf.acegisecurity.Authentication" %>
+<%@ page import="net.sf.acegisecurity.GrantedAuthority" %>
+<%@ page import="net.sf.acegisecurity.adapters.AuthByAdapter" %>
+
+<% 
+		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+		if (auth != null) { %>
+			Authentication object is of type: <%= auth.getClass().getName() %><BR><BR>
+			Authentication object as a String: <%= auth.toString() %><BR><BR>
+			
+			Authentication object holds the following granted authorities:<BR><BR>
+<%			GrantedAuthority[] granted = auth.getAuthorities();
+			for (int i = 0; i < granted.length; i++) { %>
+				<%= granted[i].toString() %> (getAuthority(): <%= granted[i].getAuthority() %>)<BR>
+<%			}
+
+			if (auth instanceof AuthByAdapter) { %>
+				<BR><B>SUCCESS! Your container adapter appears to be properly configured!</B><BR><BR>
+<%			} else { %>
+				<BR><B>SUCCESS! Your web filters appear to be properly configured!</B><BR>
+<%			}
+			
+		} else { %>
+			Authentication object is null.<BR>
+			This is an error and your Acegi Security application will not operate properly until corrected.<BR><BR>
+<%		}
+%>

+ 183 - 0
samples/contacts-tiger/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml

@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Application context containing authentication, channel
+  - security and web URI beans.
+  -
+  - Only used by "filter" artifact.
+  -
+  - $Id$
+  -->
+
+<beans>
+
+   <!-- ======================== FILTER CHAIN ======================= -->
+
+	<!--  if you wish to use channel security, add "channelProcessingFilter," in front
+	      of "httpSessionContextIntegrationFilter" in the list below -->
+	<bean id="filterChainProxy" class="net.sf.acegisecurity.util.FilterChainProxy">
+      <property name="filterInvocationDefinitionSource">
+         <value>
+		    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
+		    PATTERN_TYPE_APACHE_ANT
+            /**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,securityEnforcementFilter
+         </value>
+      </property>
+    </bean>
+
+   <!-- ======================== AUTHENTICATION ======================= -->
+
+   <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
+      <property name="providers">
+         <list>
+            <ref local="daoAuthenticationProvider"/>
+            <ref local="anonymousAuthenticationProvider"/>
+             <ref local="rememberMeAuthenticationProvider"/>
+         </list>
+      </property>
+   </bean>
+
+   <bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
+      <property name="dataSource"><ref bean="dataSource"/></property>
+   </bean>
+
+   <bean id="passwordEncoder" class="net.sf.acegisecurity.providers.encoding.Md5PasswordEncoder"/>
+
+   <bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
+      <property name="authenticationDao"><ref local="jdbcDaoImpl"/></property>
+      <property name="userCache"><ref local="userCache"/></property>
+      <property name="passwordEncoder"><ref local="passwordEncoder"/></property>
+   </bean>
+
+   <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
+    
+   <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
+      <property name="cacheManager">
+         <ref local="cacheManager"/>
+      </property>
+      <property name="cacheName">
+         <value>userCache</value>
+      </property>
+   </bean>
+   
+   <bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
+      <property name="cache"><ref local="userCacheBackend"/></property>
+   </bean>
+
+   <!-- Automatically receives AuthenticationEvent messages from DaoAuthenticationProvider -->
+   <bean id="loggerListener" class="net.sf.acegisecurity.providers.dao.event.LoggerListener"/>
+
+   <bean id="basicProcessingFilter" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter">
+      <property name="authenticationManager"><ref local="authenticationManager"/></property>
+      <property name="authenticationEntryPoint"><ref local="basicProcessingFilterEntryPoint"/></property>
+   </bean>
+
+   <bean id="basicProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
+      <property name="realmName"><value>Contacts Realm</value></property>
+   </bean>
+
+   <bean id="anonymousProcessingFilter" class="net.sf.acegisecurity.providers.anonymous.AnonymousProcessingFilter">
+      <property name="key"><value>foobar</value></property>
+      <property name="userAttribute"><value>anonymousUser,ROLE_ANONYMOUS</value></property>
+   </bean>
+
+   <bean id="anonymousAuthenticationProvider" class="net.sf.acegisecurity.providers.anonymous.AnonymousAuthenticationProvider">
+      <property name="key"><value>foobar</value></property>
+   </bean>
+
+   <bean id="httpSessionContextIntegrationFilter" class="net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter">
+   </bean>
+
+   <bean id="rememberMeProcessingFilter" class="net.sf.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
+      <property name="rememberMeServices"><ref local="rememberMeServices"/></property>
+   </bean>
+
+   <bean id="rememberMeServices" class="net.sf.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
+      <property name="authenticationDao"><ref local="jdbcDaoImpl"/></property>
+      <property name="key"><value>springRocks</value></property>
+   </bean>
+   
+   <bean id="rememberMeAuthenticationProvider" class="net.sf.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
+      <property name="key"><value>springRocks</value></property>
+   </bean>
+
+   <!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
+
+   <!-- You will need to uncomment the "Acegi Channel Processing Filter"
+        <filter-mapping> in web.xml for the following beans to be used -->
+
+   <bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">
+      <property name="channelDecisionManager"><ref local="channelDecisionManager"/></property>
+      <property name="filterInvocationDefinitionSource">
+         <value>
+			    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
+				\A/secure/.*\Z=REQUIRES_SECURE_CHANNEL
+				\A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL
+				\A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL
+				\A.*\Z=REQUIRES_INSECURE_CHANNEL
+         </value>
+      </property>
+   </bean>
+
+   <bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl">
+      <property name="channelProcessors">
+         <list>
+            <ref local="secureChannelProcessor"/>
+            <ref local="insecureChannelProcessor"/>
+         </list>
+      </property>
+   </bean>
+
+   <bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/>
+   <bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/>
+
+   <!-- ===================== HTTP REQUEST SECURITY ==================== -->
+
+   <bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
+      <property name="filterSecurityInterceptor"><ref local="filterInvocationInterceptor"/></property>
+      <property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
+   </bean>
+
+   <bean id="authenticationProcessingFilter" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
+      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+      <property name="authenticationFailureUrl"><value>/acegilogin.jsp?login_error=1</value></property>
+      <property name="defaultTargetUrl"><value>/</value></property>
+      <property name="filterProcessesUrl"><value>/j_acegi_security_check</value></property>
+      <property name="rememberMeServices"><ref local="rememberMeServices"/></property>
+   </bean>
+
+   <bean id="authenticationProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
+      <property name="loginFormUrl"><value>/acegilogin.jsp</value></property>
+      <property name="forceHttps"><value>false</value></property>
+   </bean>
+
+   <bean id="httpRequestAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
+      <property name="allowIfAllAbstainDecisions"><value>false</value></property>
+      <property name="decisionVoters">
+         <list>
+            <ref bean="roleVoter"/>
+         </list>
+      </property>
+   </bean>
+
+   <!-- Note the order that entries are placed against the objectDefinitionSource is critical.
+        The FilterSecurityInterceptor will work from the top of the list down to the FIRST pattern that matches the request URL.
+        Accordingly, you should place MOST SPECIFIC (ie a/b/c/d.*) expressions first, with LEAST SPECIFIC (ie a/.*) expressions last -->
+   <bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
+      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
+      <property name="accessDecisionManager"><ref local="httpRequestAccessDecisionManager"/></property>
+      <property name="objectDefinitionSource">
+         <value>
+			    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
+			    PATTERN_TYPE_APACHE_ANT
+			    /index.jsp=ROLE_ANONYMOUS,ROLE_USER
+			    /hello.htm=ROLE_ANONYMOUS,ROLE_USER
+			    /logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
+			    /acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER
+				/**=ROLE_USER
+         </value>
+      </property>
+   </bean>
+
+</beans>

+ 184 - 0
samples/contacts-tiger/src/main/webapp/filter/WEB-INF/applicationContext-annotations.xml

@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Application context containing authentication beans.
+  -
+  - $Id$
+  -->
+
+<beans>
+
+   <!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
+
+   <!-- ACL permission masks used by this application -->
+   <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
+      <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
+   </bean>
+   <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
+      <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
+   </bean>
+   <bean id="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
+      <property name="staticField"><value>net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE</value></property>
+   </bean>
+
+
+   <!-- An access decision voter that reads ROLE_* configuration settings -->
+   <bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
+
+   <!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
+   <bean id="aclContactReadVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
+      <property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
+      <property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
+        </list>
+      </property>
+   </bean>
+
+   <!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
+   <bean id="aclContactDeleteVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
+      <property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
+      <property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/>
+        </list>
+      </property>
+   </bean>
+
+   <!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
+   <bean id="aclContactAdminVoter" class="net.sf.acegisecurity.vote.BasicAclEntryVoter">
+      <property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
+      <property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+        </list>
+      </property>
+   </bean>
+
+   <!-- An access decision manager used by the business objects -->
+   <bean id="businessAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
+      <property name="allowIfAllAbstainDecisions"><value>false</value></property>
+      <property name="decisionVoters">
+         <list>
+            <ref local="roleVoter"/>
+            <ref local="aclContactReadVoter"/>
+            <ref local="aclContactDeleteVoter"/>
+            <ref local="aclContactAdminVoter"/>
+         </list>
+      </property>
+   </bean>
+
+   <!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
+
+   <bean id="aclManager" class="net.sf.acegisecurity.acl.AclProviderManager">
+      <property name="providers">
+         <list>
+            <ref local="basicAclProvider"/>
+         </list>
+      </property>
+   </bean>
+
+   <bean id="basicAclProvider" class="net.sf.acegisecurity.acl.basic.BasicAclProvider">
+      <property name="basicAclDao"><ref local="basicAclExtendedDao"/></property>
+   </bean>
+
+   <bean id="basicAclExtendedDao" class="net.sf.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
+      <property name="dataSource"><ref bean="dataSource"/></property>
+   </bean>
+
+   <!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
+
+   <bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
+      <property name="providers">
+         <list>
+            <ref local="afterAclRead"/>
+            <ref local="afterAclCollectionRead"/>
+         </list>
+      </property>
+   </bean>
+   
+   <!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
+   <bean id="afterAclCollectionRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
+        </list>
+      </property>
+   </bean>
+   
+   <!-- Processes AFTER_ACL_READ configuration settings -->
+   <bean id="afterAclRead" class="net.sf.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
+      <property name="aclManager"><ref local="aclManager"/></property>
+      <property name="requirePermission">
+        <list>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
+          <ref local="net.sf.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
+        </list>
+      </property>
+   </bean>
+
+
+    <!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
+
+	<bean id="attributes" class="net.sf.acegisecurity.annotation.SecurityAnnotationAttributes"/>
+	
+	<bean id="objectDefinitionSource" class="net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes">
+		<property name="attributes"><ref local="attributes"/></property>
+	</bean>
+
+	<!-- We don't validate config attributes, as it's unsupported by MethodDefinitionAttributes -->
+	<bean id="securityInterceptor" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
+    	<property name="validateConfigAttributes"><value>false</value></property>
+    	<property name="authenticationManager"><ref bean="authenticationManager"/></property>
+    	<property name="accessDecisionManager"><ref bean="businessAccessDecisionManager"/></property>
+    	<property name="afterInvocationManager"><ref bean="afterInvocationManager"/></property>
+ 		<property name="objectDefinitionSource"><ref bean="objectDefinitionSource"/></property>
+	</bean>
+	
+	<!--
+		This bean is a postprocessor that will automatically apply relevant advisors
+		to any bean in child factories.
+	-->
+	<bean id="autoproxy" 
+		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
+	</bean>
+
+	<!--
+		AOP advisor that will automatically wire the MethodSecurityInterceptor (above)
+		The configuration attributes used are obtained from the securityInterceptor.objectDefinitionSouce, 
+		which in the above configuration is a JDK 5 Annotations Attributes-based source.
+	-->
+	<bean id="methodSecurityAdvisor"
+		class="net.sf.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor"
+		autowire="constructor" >
+	</bean>
+		   
+	<!--
+		AOP advisor used for declarative transaction management
+	-->
+	<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
+		<property name="transactionInterceptor" ref="transactionInterceptor"/>
+	</bean>
+
+	<!--
+		Transaction interceptor to use for auto-proxy creation
+	-->
+	<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
+		<property name="transactionManager" ref="transactionManager"/>
+		<property name="transactionAttributeSource">
+			<bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
+		</property>
+	</bean>		   
+
+</beans>

+ 48 - 0
samples/contacts-tiger/src/main/webapp/filter/WEB-INF/applicationContext-business.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
+
+<!--
+  - Application context containing business beans.
+  -
+  - Used by all artifacts.
+  -
+  - $Id$
+  -->
+
+<beans>
+
+    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+        <property name="driverClassName">
+            <value>org.hsqldb.jdbcDriver</value>
+        </property>
+        <property name="url">
+            <value>jdbc:hsqldb:mem:contacts</value>
+        </property>
+        <property name="username">
+            <value>sa</value>
+        </property>
+        <property name="password">
+            <value></value>
+        </property>
+    </bean>
+	
+	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+		<property name="dataSource"><ref local="dataSource"/></property>
+	</bean>
+	
+   <bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
+	   <property name="dataSource"><ref local="dataSource"/></property>
+   </bean>
+   
+   <bean id="contactDao" class="sample.contact.ContactDaoSpring">
+	   <property name="dataSource"><ref local="dataSource"/></property>
+   </bean>
+   
+   
+   <!-- Advised Contact Manager using Java 5 Annotations --> 
+   <bean id="contactManager" class="sample.contact.annotation.ContactManagerBackend">
+	   <property name="contactDao"><ref local="contactDao"/></property>
+	   <property name="basicAclExtendedDao"><ref bean="basicAclExtendedDao"/></property>
+   </bean>
+
+</beans>

+ 107 - 0
samples/contacts-tiger/src/main/webapp/filter/WEB-INF/web.xml

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN' 'http://java.sun.com/dtd/web-app_2_3.dtd'>
+
+<!--
+  - Contacts web application using Java 5 Annotations
+  -
+  - web.xml for "filter" artifact only.
+  -
+  - $Id$
+  -->
+
+<web-app>
+
+    <display-name>Contacts Sample Application</display-name>
+    
+	<!--
+	  - Location of the XML file that defines the root application context
+	  - Applied by ContextLoaderListener.
+	  -->
+	<context-param>
+		<param-name>contextConfigLocation</param-name>
+		<param-value>
+			/WEB-INF/applicationContext-acegi-security.xml
+			/WEB-INF/applicationContext-business.xml
+			/WEB-INF/applicationContext-annotations.xml
+		</param-value>
+	</context-param>
+	
+	<context-param>
+		<param-name>log4jConfigLocation</param-name>
+		<param-value>/WEB-INF/classes/log4j.properties</param-value>
+	</context-param>
+
+   <filter>
+        <filter-name>Acegi Filter Chain Proxy</filter-name>
+        <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
+        <init-param>
+            <param-name>targetClass</param-name>
+            <param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>
+        </init-param>
+   </filter>
+
+    <filter-mapping>
+      <filter-name>Acegi Filter Chain Proxy</filter-name>
+      <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+	<!--
+	  - Loads the root application context of this web app at startup.
+	  - The application context is then available via 
+	  - WebApplicationContextUtils.getWebApplicationContext(servletContext).
+    -->
+	<listener>
+		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+	</listener>
+
+	<listener>
+		<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
+	</listener>
+
+    <!--
+        The HttpSessionEventPublisher will publish
+        HttpSessionCreatedEvent and HttpSessionDestroyedEvent
+        to the WebApplicationContext
+ -->  
+    <listener>
+        <listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
+    </listener>
+ 
+  <!--
+	- Provides core MVC application controller. See contacts-servlet.xml.
+    -->
+	<servlet>
+		<servlet-name>contacts</servlet-name>
+		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+		<load-on-startup>1</load-on-startup>
+	</servlet>
+
+  <!--
+    - Provides web services endpoint. See remoting-servlet.xml.
+    -->
+	<servlet>
+		<servlet-name>remoting</servlet-name>
+		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+		<load-on-startup>2</load-on-startup>
+	</servlet>
+
+	<servlet-mapping>
+    	<servlet-name>contacts</servlet-name>
+    	<url-pattern>*.htm</url-pattern>
+ 	</servlet-mapping>
+  
+	<servlet-mapping>
+		<servlet-name>remoting</servlet-name>
+		<url-pattern>/remoting/*</url-pattern>
+	</servlet-mapping>
+
+ 	<welcome-file-list>
+		<welcome-file>index.jsp</welcome-file>
+	</welcome-file-list>
+
+  	<taglib>
+      <taglib-uri>/spring</taglib-uri>
+      <taglib-location>/WEB-INF/spring.tld</taglib-location>
+  	</taglib>
+
+</web-app>

+ 48 - 0
samples/contacts-tiger/src/main/webapp/filter/acegilogin.jsp

@@ -0,0 +1,48 @@
+<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
+<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
+<%@ page import="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter" %>
+<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
+
+<html>
+  <head>
+    <title>Login</title>
+  </head>
+
+  <body>
+    <h1>Login</h1>
+
+	<P>Valid users:
+	<P>
+	<P>username <b>marissa</b>, password <b>koala</b>
+	<P>username <b>dianne</b>, password <b>emu</b>
+	<p>username <b>scott</b>, password <b>wombat</b>
+	<p>username <b>peter</b>, password <b>opal</b> (user disabled)
+	<p>username <b>bill</b>, password <b>wombat</b>
+	<p>username <b>bob</b>, password <b>wombat</b>
+	<p>username <b>jane</b>, password <b>wombat</b>
+	<p>
+	
+    <%-- this form-login-page form is also used as the 
+         form-error-page to ask for a login again.
+         --%>
+    <c:if test="${not empty param.login_error}">
+      <font color="red">
+        Your login attempt was not successful, try again.<BR><BR>
+        Reason: <%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
+      </font>
+    </c:if>
+
+    <form action="<c:url value='j_acegi_security_check'/>" method="POST">
+      <table>
+        <tr><td>User:</td><td><input type='text' name='j_username' <c:if test="${not empty param.login_error}">value='<%= session.getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY) %>'</c:if>></td></tr>
+        <tr><td>Password:</td><td><input type='password' name='j_password'></td></tr>
+        <tr><td><input type="checkbox" name="_acegi_security_remember_me"></td><td>Don't ask for my password for two weeks</td></tr>
+
+        <tr><td colspan='2'><input name="submit" type="submit"></td></tr>
+        <tr><td colspan='2'><input name="reset" type="reset"></td></tr>
+      </table>
+
+    </form>
+
+  </body>
+</html>

+ 5 - 0
samples/contacts-tiger/src/main/webapp/filter/error.html

@@ -0,0 +1,5 @@
+<html>
+	<title>Access denied!</title>
+	<h1>Access Denied</h1>
+	We're sorry, but you are not authorized to perform the requested operation.
+</html>

+ 45 - 0
samples/contacts-tiger/src/main/webapp/filter/exitUser.jsp

@@ -0,0 +1,45 @@
+<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
+
+<%@ page import="net.sf.acegisecurity.context.SecurityContextHolder" %>
+<%@ page import="net.sf.acegisecurity.Authentication" %>
+<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
+<%@ page import="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter" %>
+<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
+
+<html>
+  <head>
+    <title>Exit User</title>
+  </head>
+
+  <body>
+    <h1>Exit User</h1>
+
+    <c:if test="${not empty param.login_error}">
+      <font color="red">
+        Your 'Exit User' attempt was not successful, try again.<BR><BR>
+        Reason: <%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
+      </font>
+    </c:if>
+
+    <form action="<c:url value='j_acegi_exit_user'/>" method="POST">
+      <table>
+        <tr><td>Current User:</td><td>
+
+         <% 
+			Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+			if (auth != null) { %>
+			
+			<%= auth.getPrincipal().toString() %>
+			
+		<% } %>
+		
+			
+         
+         </td></tr>
+        <tr><td colspan='2'><input name="exit" type="submit" value="Exit"></td></tr>
+      </table>
+
+    </form>
+
+  </body>
+</html>

+ 43 - 0
samples/contacts-tiger/src/main/webapp/filter/switchUser.jsp

@@ -0,0 +1,43 @@
+<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
+<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
+<%@ page import="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter" %>
+<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
+
+<html>
+  <head>
+    <title>Switch User</title>
+  </head>
+
+  <body>
+    <h1>Switch to User</h1>
+
+	<P>Valid users:
+	<P>
+	<P>username <b>marissa</b>, password <b>koala</b>
+	<P>username <b>dianne</b>, password <b>emu</b>
+	<p>username <b>scott</b>, password <b>wombat</b>
+	<p>username <b>bill</b>, password <b>wombat</b>
+	<p>username <b>bob</b>, password <b>wombat</b>
+	<p>username <b>jane</b>, password <b>wombat</b>
+	<p>
+	
+    <%-- this form-login-page form is also used as the 
+         form-error-page to ask for a login again.
+         --%>
+    <c:if test="${not empty param.login_error}">
+      <font color="red">
+        Your 'su' attempt was not successful, try again.<BR><BR>
+        Reason: <%= ((AuthenticationException) session.getAttribute(AbstractProcessingFilter.ACEGI_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
+      </font>
+    </c:if>
+
+    <form action="<c:url value='j_acegi_switch_user'/>" method="POST">
+      <table>
+        <tr><td>User:</td><td><input type='text' name='j_username'></td></tr>
+        <tr><td colspan='2'><input name="switch" type="submit" value="Switch to User"></td></tr>
+      </table>
+
+    </form>
+
+  </body>
+</html>