1
0
mirror of synced 2026-08-06 10:18:52 +00:00

SEC-239: New ACL module.

This commit is contained in:
Ben Alex
2006-11-17 02:01:21 +00:00
parent 2984913051
commit 9f512c384e
94 changed files with 5759 additions and 3676 deletions
@@ -12,15 +12,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact.annotation;
import org.acegisecurity.Authentication;
import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acl.basic.BasicAclExtendedDao;
import org.acegisecurity.acl.basic.NamedEntityObjectIdentity;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.annotation.Secured;
@@ -54,28 +59,36 @@ import java.util.Random;
public class ContactManagerBackend extends ApplicationObjectSupport implements ContactManager, InitializingBean {
//~ Instance fields ================================================================================================
private BasicAclExtendedDao basicAclExtendedDao;
private ContactDao contactDao;
private int counter = 100;
// TODO: Assignment of annotations against class does not result in match in sample application
private MutableAclService mutableAclService;
private int counter = 1000;
//~ Methods ========================================================================================================
@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);
public void addPermission(Contact contact, Sid recipient, Permission permission) {
MutableAcl acl;
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
try {
acl = (MutableAcl) mutableAclService.readAclById(oid);
} catch (NotFoundException nfe) {
acl = mutableAclService.createAcl(oid);
}
acl.insertAce(null, permission, recipient, true);
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Added permission " + permission + " for recipient " + recipient + " contact " + contact);
logger.debug("Added permission " + permission + " for Sid " + recipient + " contact " + contact);
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactDao, "contactDao required");
Assert.notNull(basicAclExtendedDao, "basicAclExtendedDao required");
Assert.notNull(mutableAclService, "mutableAclService required");
}
@Secured({"ROLE_USER"})
@@ -84,8 +97,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contact.setId(new Long(counter++));
contactDao.create(contact);
// Grant the current principal access to the contact
addPermission(contact, getUsername(), new Integer(SimpleAclEntry.ADMINISTRATION));
// Grant the current principal administrative permission to the contact
addPermission(contact, new PrincipalSid(getUsername()), BasePermission.ADMINISTRATION);
if (logger.isDebugEnabled()) {
logger.debug("Created contact " + contact + " and granted admin permission to recipient " + getUsername());
@@ -97,7 +110,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contactDao.delete(contact.getId());
// Delete the ACL information as well
basicAclExtendedDao.delete(makeObjectIdentity(contact));
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
mutableAclService.deleteAcl(oid, false);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " including ACL permissions");
@@ -105,8 +119,20 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
@Secured({"ACL_CONTACT_ADMIN"})
public void deletePermission(Contact contact, String recipient) {
basicAclExtendedDao.delete(makeObjectIdentity(contact), recipient);
public void deletePermission(Contact contact, Sid recipient, Permission permission) {
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(oid);
// Remove all permissions associated with this particular recipient (string equality to KISS)
AccessControlEntry[] entries = acl.getEntries();
for (int i = 0; i < entries.length; i++) {
if (entries[i].getSid().equals(recipient) && entries[i].getPermission().equals(permission)) {
acl.deleteAce(entries[i].getId());
}
}
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " ACL permissions for recipient " + recipient);
@@ -131,15 +157,10 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
List list = contactDao.findAllPrincipals();
list.addAll(contactDao.findAllRoles());
return list;
}
public BasicAclExtendedDao getBasicAclExtendedDao() {
return basicAclExtendedDao;
}
@Secured({"ROLE_USER", "AFTER_ACL_READ"})
@Transactional(readOnly = true)
public Contact getById(Long id) {
@@ -150,10 +171,6 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
return contactDao.getById(id);
}
public ContactDao getContactDao() {
return contactDao;
}
/**
* This is a public method.
*
@@ -181,18 +198,14 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
}
private AclObjectIdentity makeObjectIdentity(Contact contact) {
return new NamedEntityObjectIdentity(contact.getClass().getName(), contact.getId().toString());
}
public void setBasicAclExtendedDao(BasicAclExtendedDao basicAclExtendedDao) {
this.basicAclExtendedDao = basicAclExtendedDao;
}
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
public void setMutableAclService(MutableAclService mutableAclService) {
this.mutableAclService = mutableAclService;
}
public void update(Contact contact) {
contactDao.update(contact);
@@ -1,163 +0,0 @@
<?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>
@@ -1,72 +0,0 @@
<?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>
@@ -21,7 +21,7 @@
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,basicProcessingFilter,rememberMeProcessingFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
/**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,switchUserProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
@@ -38,7 +38,7 @@
</property>
</bean>
<bean id="jdbcDaoImpl" class="org.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
<bean id="jdbcDaoImpl" class="org.acegisecurity.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
@@ -90,6 +90,7 @@
</bean>
<bean id="rememberMeProcessingFilter" class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="authenticationManager"><ref local="authenticationManager"/></property>
<property name="rememberMeServices"><ref local="rememberMeServices"/></property>
</bean>
@@ -101,6 +102,18 @@
<bean id="rememberMeAuthenticationProvider" class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key"><value>springRocks</value></property>
</bean>
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg value="/index.jsp"/> <!-- URL redirected to after logout -->
<constructor-arg>
<list>
<ref bean="rememberMeServices"/>
<bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
<bean id="securityContextHolderAwareRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter"/>
<!-- ===================== HTTP CHANNEL REQUIREMENTS ==================== -->
@@ -136,6 +149,11 @@
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint"><ref local="authenticationProcessingFilterEntryPoint"/></property>
<property name="accessDeniedHandler">
<bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
<property name="errorPage" value="/accessDenied.jsp"/>
</bean>
</property>
</bean>
<bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
@@ -173,10 +191,22 @@
/index.jsp=ROLE_ANONYMOUS,ROLE_USER
/hello.htm=ROLE_ANONYMOUS,ROLE_USER
/logoff.jsp=ROLE_ANONYMOUS,ROLE_USER
/switchuser.jsp=ROLE_SUPERVISOR
/j_acegi_switch_user=ROLE_SUPERVISOR
/acegilogin.jsp*=ROLE_ANONYMOUS,ROLE_USER
/**=ROLE_USER
</value>
</property>
</bean>
<!-- Filter used to switch the user context. Note: the switch and exit url must be secured
based on the role granted the ability to 'switch' to another user -->
<!-- In this example 'marissa' has ROLE_SUPERVISOR that can switch to regular ROLE_USER(s) -->
<bean id="switchUserProcessingFilter" class="org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter">
<property name="userDetailsService" ref="jdbcDaoImpl" />
<property name="switchUserUrl"><value>/j_acegi_switch_user</value></property>
<property name="exitUserUrl"><value>/j_acegi_exit_user</value></property>
<property name="targetUrl"><value>/acegi-security-sample-contacts-filter/secure/index.htm</value></property>
</bean>
</beans>
@@ -12,60 +12,72 @@
<!-- ~~~~~~~~~~~~~~~~~~ "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 id="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.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 id="org.acegisecurity.acls.domain.BasePermission.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.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 id="org.acegisecurity.acls.domain.BasePermission.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.DELETE</value></property>
</bean>
<!-- An access decision voter that reads ROLE_* configuration settings -->
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
<bean id="roleVoter" class="org.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>
<bean id="aclContactReadVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_READ</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
<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>
<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_DELETE</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.DELETE"/>
</list>
</constructor-arg>
<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>
<bean id="aclContactAdminVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_ADMIN</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
</list>
</constructor-arg>
<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">
<bean id="businessAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions"><value>false</value></property>
<property name="decisionVoters">
<list>
@@ -79,25 +91,53 @@
<!-- ========= 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>
<bean id="aclCache" class="org.acegisecurity.acls.jdbc.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName">
<value>aclCache</value>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="lookupStrategy" class="org.acegisecurity.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.acegisecurity.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.acegisecurity.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="aclService" class="org.acegisecurity.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
<bean id="afterInvocationManager" class="net.sf.acegisecurity.afterinvocation.AfterInvocationProviderManager">
<bean id="afterInvocationManager" class="org.acegisecurity.afterinvocation.AfterInvocationProviderManager">
<property name="providers">
<list>
<ref local="afterAclRead"/>
@@ -107,38 +147,41 @@
</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 id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</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 id="afterAclRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
<bean id="attributes" class="net.sf.acegisecurity.annotation.SecurityAnnotationAttributes"/>
<bean id="attributes" class="org.acegisecurity.annotation.SecurityAnnotationAttributes"/>
<bean id="objectDefinitionSource" class="net.sf.acegisecurity.intercept.method.MethodDefinitionAttributes">
<bean id="objectDefinitionSource" class="org.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">
<bean id="securityInterceptor" class="org.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>
@@ -160,7 +203,7 @@
which in the above configuration is a JDK 5 Annotations Attributes-based source.
-->
<bean id="methodSecurityAdvisor"
class="net.sf.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor"
class="org.acegisecurity.intercept.method.aopalliance.MethodDefinitionSourceAdvisor"
autowire="constructor" >
</bean>
@@ -31,7 +31,9 @@
</bean>
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="dataSource" ref="dataSource"/>
<property name="mutableAclService" ref="aclService"/>
<property name="platformTransactionManager" ref="transactionManager"/>
</bean>
<bean id="contactDao" class="sample.contact.ContactDaoSpring">
@@ -42,7 +44,7 @@
<!-- 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>
<property name="mutableAclService"><ref bean="aclService"/></property>
</bean>
</beans>
@@ -33,10 +33,10 @@
<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>
@@ -64,7 +64,7 @@
to the WebApplicationContext
-->
<listener>
<listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
<listener-class>org.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
</listener>
<!--
@@ -0,0 +1,16 @@
<%@ page import="org.acegisecurity.context.SecurityContextHolder" %>
<%@ page import="org.acegisecurity.Authentication" %>
<%@ page import="org.acegisecurity.ui.AccessDeniedHandlerImpl" %>
<h1>Sorry, access is denied</h1>
<p>
<%= request.getAttribute(AccessDeniedHandlerImpl.ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY)%>
<p>
<% Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
Authentication object as a String: <%= auth.toString() %><BR><BR>
<% } %>
@@ -1,5 +0,0 @@
<html>
<title>Access denied!</title>
<h1>Access Denied</h1>
We're sorry, but you are not authorized to perform the requested operation.
</html>
@@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.basic.SimpleAclEntry;
@@ -28,7 +27,7 @@ public class AddPermission {
//~ Instance fields ================================================================================================
public Contact contact;
public Integer permission = new Integer(SimpleAclEntry.NOTHING);
public Integer permission = new Integer(SimpleAclEntry.READ);
public String recipient;
//~ Methods ========================================================================================================
@@ -12,10 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.springframework.beans.factory.InitializingBean;
@@ -59,7 +60,7 @@ public class AddPermissionController extends SimpleFormController implements Ini
protected ModelAndView disallowDuplicateFormSubmission(HttpServletRequest request, HttpServletResponse response)
throws Exception {
BindException errors = new BindException(formBackingObject(request), getCommandName());
errors.reject("err.duplicateFormSubmission", "Duplicate form submission.");
errors.reject("err.duplicateFormSubmission", "Duplicate form submission. *");
return showForm(request, response, errors);
}
@@ -76,10 +77,6 @@ public class AddPermissionController extends SimpleFormController implements Ini
return addPermission;
}
public ContactManager getContactManager() {
return contactManager;
}
protected ModelAndView handleInvalidSubmit(HttpServletRequest request, HttpServletResponse response)
throws Exception {
return disallowDuplicateFormSubmission(request, response);
@@ -87,16 +84,12 @@ public class AddPermissionController extends SimpleFormController implements Ini
private Map listPermissions(HttpServletRequest request) {
Map map = new LinkedHashMap();
map.put(new Integer(SimpleAclEntry.NOTHING),
getApplicationContext().getMessage("select.none", null, "None", request.getLocale()));
map.put(new Integer(SimpleAclEntry.ADMINISTRATION),
map.put(new Integer(BasePermission.ADMINISTRATION.getMask()),
getApplicationContext().getMessage("select.administer", null, "Administer", request.getLocale()));
map.put(new Integer(SimpleAclEntry.READ),
map.put(new Integer(BasePermission.READ.getMask()),
getApplicationContext().getMessage("select.read", null, "Read", request.getLocale()));
map.put(new Integer(SimpleAclEntry.DELETE),
map.put(new Integer(BasePermission.DELETE.getMask()),
getApplicationContext().getMessage("select.delete", null, "Delete", request.getLocale()));
map.put(new Integer(SimpleAclEntry.READ_WRITE_DELETE),
getApplicationContext().getMessage("select.readWriteDelete", null, "Read+Write+Delete", request.getLocale()));
return map;
}
@@ -120,13 +113,14 @@ public class AddPermissionController extends SimpleFormController implements Ini
BindException errors) throws Exception {
AddPermission addPermission = (AddPermission) command;
PrincipalSid sid = new PrincipalSid(addPermission.getRecipient());
Permission permission = BasePermission.buildFromMask(addPermission.getPermission().intValue());
try {
contactManager.addPermission(addPermission.getContact(), addPermission.getRecipient(),
addPermission.getPermission());
contactManager.addPermission(addPermission.getContact(), sid, permission);
} catch (DataAccessException existingPermission) {
existingPermission.printStackTrace();
errors.rejectValue("recipient", "err.recipientExistsForContact",
"This recipient already has permissions to this contact.");
errors.rejectValue("recipient", "err.recipientExistsForContact", "Addition failure.");
return showForm(request, response, errors);
}
@@ -12,10 +12,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.domain.BasePermission;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
@@ -44,9 +43,8 @@ public class AddPermissionValidator implements Validator {
if (addPermission.getPermission() != null) {
int permission = addPermission.getPermission().intValue();
if ((permission != SimpleAclEntry.NOTHING) && (permission != SimpleAclEntry.ADMINISTRATION)
&& (permission != SimpleAclEntry.READ) && (permission != SimpleAclEntry.DELETE)
&& (permission != SimpleAclEntry.READ_WRITE_DELETE)) {
if ((permission != BasePermission.ADMINISTRATION.getMask())
&& (permission != BasePermission.READ.getMask()) && (permission != BasePermission.DELETE.getMask())) {
errors.rejectValue("permission", "err.permission.invalid", "The indicated permission is invalid. *");
}
}
@@ -12,11 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.AclEntry;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acls.Acl;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.beans.factory.InitializingBean;
@@ -45,22 +45,14 @@ import javax.servlet.http.HttpServletResponse;
public class AdminPermissionController implements Controller, InitializingBean {
//~ Instance fields ================================================================================================
private AclManager aclManager;
private AclService aclService;
private ContactManager contactManager;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactManager, "A ContactManager implementation is required");
Assert.notNull(aclManager, "An aclManager implementation is required");
}
public AclManager getAclManager() {
return aclManager;
}
public ContactManager getContactManager() {
return contactManager;
Assert.notNull(aclService, "An aclService implementation is required");
}
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
@@ -68,17 +60,17 @@ public class AdminPermissionController implements Controller, InitializingBean {
int id = RequestUtils.getRequiredIntParameter(request, "contactId");
Contact contact = contactManager.getById(new Long(id));
AclEntry[] acls = aclManager.getAcls(contact);
Acl acl = aclService.readAclById(new ObjectIdentityImpl(contact));
Map model = new HashMap();
model.put("contact", contact);
model.put("acls", acls);
model.put("acl", acl);
return new ModelAndView("adminPermission", "model", model);
}
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
public void setAclService(AclService aclService) {
this.aclService = aclService;
}
public void setContactManager(ContactManager contact) {
@@ -12,9 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.sid.Sid;
import java.util.List;
@@ -27,13 +29,13 @@ import java.util.List;
public interface ContactManager {
//~ Methods ========================================================================================================
public void addPermission(Contact contact, String recipient, Integer permission);
public void addPermission(Contact contact, Sid recipient, Permission permission);
public void create(Contact contact);
public void delete(Contact contact);
public void deletePermission(Contact contact, String recipient);
public void deletePermission(Contact contact, Sid recipient, Permission permission);
public List getAll();
@@ -12,15 +12,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.Authentication;
import org.acegisecurity.acl.basic.AclObjectIdentity;
import org.acegisecurity.acl.basic.BasicAclExtendedDao;
import org.acegisecurity.acl.basic.NamedEntityObjectIdentity;
import org.acegisecurity.acl.basic.SimpleAclEntry;
import org.acegisecurity.acls.AccessControlEntry;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.NotFoundException;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.acegisecurity.context.SecurityContextHolder;
@@ -45,27 +50,33 @@ import java.util.Random;
public class ContactManagerBackend extends ApplicationObjectSupport implements ContactManager, InitializingBean {
//~ Instance fields ================================================================================================
private BasicAclExtendedDao basicAclExtendedDao;
private ContactDao contactDao;
private MutableAclService mutableAclService;
private int counter = 1000;
//~ Methods ========================================================================================================
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);
public void addPermission(Contact contact, Sid recipient, Permission permission) {
MutableAcl acl;
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
try {
acl = (MutableAcl) mutableAclService.readAclById(oid);
} catch (NotFoundException nfe) {
acl = mutableAclService.createAcl(oid);
}
acl.insertAce(null, permission, recipient, true);
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Added permission " + permission + " for recipient " + recipient + " contact " + contact);
logger.debug("Added permission " + permission + " for Sid " + recipient + " contact " + contact);
}
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactDao, "contactDao required");
Assert.notNull(basicAclExtendedDao, "basicAclExtendedDao required");
Assert.notNull(mutableAclService, "mutableAclService required");
}
public void create(Contact contact) {
@@ -73,8 +84,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contact.setId(new Long(counter++));
contactDao.create(contact);
// Grant the current principal access to the contact
addPermission(contact, getUsername(), new Integer(SimpleAclEntry.ADMINISTRATION));
// Grant the current principal administrative permission to the contact
addPermission(contact, new PrincipalSid(getUsername()), BasePermission.ADMINISTRATION);
if (logger.isDebugEnabled()) {
logger.debug("Created contact " + contact + " and granted admin permission to recipient " + getUsername());
@@ -85,15 +96,28 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
contactDao.delete(contact.getId());
// Delete the ACL information as well
basicAclExtendedDao.delete(makeObjectIdentity(contact));
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
mutableAclService.deleteAcl(oid, false);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " including ACL permissions");
}
}
public void deletePermission(Contact contact, String recipient) {
basicAclExtendedDao.delete(makeObjectIdentity(contact), recipient);
public void deletePermission(Contact contact, Sid recipient, Permission permission) {
ObjectIdentity oid = new ObjectIdentityImpl(Contact.class, contact.getId());
MutableAcl acl = (MutableAcl) mutableAclService.readAclById(oid);
// Remove all permissions associated with this particular recipient (string equality to KISS)
AccessControlEntry[] entries = acl.getEntries();
for (int i = 0; i < entries.length; i++) {
if (entries[i].getSid().equals(recipient) && entries[i].getPermission().equals(permission)) {
acl.deleteAce(entries[i].getId());
}
}
mutableAclService.updateAcl(acl);
if (logger.isDebugEnabled()) {
logger.debug("Deleted contact " + contact + " ACL permissions for recipient " + recipient);
@@ -114,15 +138,10 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
List list = contactDao.findAllPrincipals();
list.addAll(contactDao.findAllRoles());
return list;
}
public BasicAclExtendedDao getBasicAclExtendedDao() {
return basicAclExtendedDao;
}
public Contact getById(Long id) {
if (logger.isDebugEnabled()) {
logger.debug("Returning contact with id: " + id);
@@ -131,10 +150,6 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
return contactDao.getById(id);
}
public ContactDao getContactDao() {
return contactDao;
}
/**
* This is a public method.
*
@@ -162,18 +177,14 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
}
}
private AclObjectIdentity makeObjectIdentity(Contact contact) {
return new NamedEntityObjectIdentity(contact.getClass().getName(), contact.getId().toString());
}
public void setBasicAclExtendedDao(BasicAclExtendedDao basicAclExtendedDao) {
this.basicAclExtendedDao = basicAclExtendedDao;
}
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
public void setMutableAclService(MutableAclService mutableAclService) {
this.mutableAclService = mutableAclService;
}
public void update(Contact contact) {
contactDao.update(contact);
@@ -12,13 +12,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.acls.MutableAcl;
import org.acegisecurity.acls.MutableAclService;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.AclImpl;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.objectidentity.ObjectIdentity;
import org.acegisecurity.acls.objectidentity.ObjectIdentityImpl;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;
import java.util.Random;
@@ -35,8 +56,10 @@ import javax.sql.DataSource;
public class DataSourcePopulator implements InitializingBean {
//~ Instance fields ================================================================================================
private DataSource dataSource;
JdbcTemplate template;
private MutableAclService mutableAclService;
Random rnd = new Random();
TransactionTemplate tt;
String[] firstNames = {
"Bob", "Mary", "James", "Jane", "Kristy", "Kirsty", "Kate", "Jeni", "Angela", "Melanie", "Kent", "William",
"Geoff", "Jeff", "Adrian", "Amanda", "Lisa", "Elizabeth", "Prue", "Richard", "Darin", "Phillip", "Michael",
@@ -47,91 +70,28 @@ public class DataSourcePopulator implements InitializingBean {
"Edwards", "Gates", "Black", "Brown", "Gray", "Marwell", "Booch", "Johnson", "McTaggart", "Parklin",
"Findlay", "Robinson", "Giugni", "Lang", "Chi", "Carmichael"
};
private int createEntities = 1000;
private int createEntities = 50;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(dataSource, "dataSource required");
Assert.notNull(mutableAclService, "mutableAclService required");
Assert.notNull(template, "dataSource required");
Assert.notNull(tt, "platformTransactionManager required");
JdbcTemplate template = new JdbcTemplate(dataSource);
// Set a user account that will initially own all the created data
Authentication authRequest = new UsernamePasswordAuthenticationToken("marissa", "koala",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_IGNORED")});
SecurityContextHolder.getContext().setAuthentication(authRequest);
template.execute(
"CREATE TABLE CONTACTS(ID BIGINT NOT NULL PRIMARY KEY, CONTACT_NAME VARCHAR_IGNORECASE(50) NOT NULL, EMAIL VARCHAR_IGNORECASE(50) NOT NULL)");
template.execute("INSERT INTO contacts VALUES (1, 'John Smith', 'john@somewhere.com');"); // marissa
template.execute("INSERT INTO contacts VALUES (2, 'Michael Citizen', 'michael@xyz.com');"); // marissa
template.execute("INSERT INTO contacts VALUES (3, 'Joe Bloggs', 'joe@demo.com');"); // marissa
template.execute("INSERT INTO contacts VALUES (4, 'Karen Sutherland', 'karen@sutherland.com');"); // marissa + dianne + scott
template.execute("INSERT INTO contacts VALUES (5, 'Mitchell Howard', 'mitchell@abcdef.com');"); // dianne
template.execute("INSERT INTO contacts VALUES (6, 'Rose Costas', 'rose@xyz.com');"); // dianne + scott
template.execute("INSERT INTO contacts VALUES (7, 'Amanda Smith', 'amanda@abcdef.com');"); // scott
template.execute("INSERT INTO contacts VALUES (8, 'Cindy Smith', 'cindy@smith.com');"); // dianne + scott
template.execute("INSERT INTO contacts VALUES (9, 'Jonathan Citizen', 'jonathan@xyz.com');"); // scott
for (int i = 10; i < createEntities; i++) {
String[] person = selectPerson();
template.execute("INSERT INTO contacts VALUES (" + i + ", '" + person[2] + "', '" + person[0].toLowerCase()
+ "@" + person[1].toLowerCase() + ".com');");
}
"CREATE TABLE ACL_SID(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,PRINCIPAL BOOLEAN NOT NULL,SID VARCHAR_IGNORECASE(100) NOT NULL,CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));");
template.execute(
"CREATE TABLE ACL_OBJECT_IDENTITY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,OBJECT_IDENTITY VARCHAR_IGNORECASE(250) NOT NULL,PARENT_OBJECT BIGINT,ACL_CLASS VARCHAR_IGNORECASE(250) NOT NULL,CONSTRAINT UNIQUE_OBJECT_IDENTITY UNIQUE(OBJECT_IDENTITY),CONSTRAINT SYS_FK_3 FOREIGN KEY(PARENT_OBJECT) REFERENCES ACL_OBJECT_IDENTITY(ID))");
"CREATE TABLE ACL_CLASS(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,CLASS VARCHAR_IGNORECASE(100) NOT NULL,CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
template.execute(
"INSERT INTO acl_object_identity VALUES (1, 'sample.contact.Contact:1', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
"CREATE TABLE ACL_OBJECT_IDENTITY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,OBJECT_ID_CLASS BIGINT NOT NULL,OBJECT_ID_IDENTITY BIGINT NOT NULL,PARENT_OBJECT BIGINT,OWNER_SID BIGINT,ENTRIES_INHERITING BOOLEAN NOT NULL,CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS,OBJECT_ID_IDENTITY),CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID),CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID),CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID));");
template.execute(
"INSERT INTO acl_object_identity VALUES (2, 'sample.contact.Contact:2', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (3, 'sample.contact.Contact:3', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (4, 'sample.contact.Contact:4', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (5, 'sample.contact.Contact:5', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (6, 'sample.contact.Contact:6', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (7, 'sample.contact.Contact:7', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (8, 'sample.contact.Contact:8', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
template.execute(
"INSERT INTO acl_object_identity VALUES (9, 'sample.contact.Contact:9', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
for (int i = 10; i < createEntities; i++) {
template.execute("INSERT INTO acl_object_identity VALUES (" + i + ", 'sample.contact.Contact:" + i
+ "', null, 'org.acegisecurity.acl.basic.SimpleAclEntry');");
}
template.execute(
"CREATE TABLE ACL_PERMISSION(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,ACL_OBJECT_IDENTITY BIGINT NOT NULL,RECIPIENT VARCHAR_IGNORECASE(100) NOT NULL,MASK INTEGER NOT NULL,CONSTRAINT UNIQUE_RECIPIENT UNIQUE(ACL_OBJECT_IDENTITY,RECIPIENT),CONSTRAINT SYS_FK_7 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID))");
template.execute("INSERT INTO acl_permission VALUES (null, 1, 'marissa', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 2, 'marissa', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 3, 'marissa', 22);"); // read+write+delete
template.execute("INSERT INTO acl_permission VALUES (null, 4, 'marissa', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 4, 'dianne', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 4, 'scott', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 5, 'dianne', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 6, 'dianne', 22);"); // read+write+delete
template.execute("INSERT INTO acl_permission VALUES (null, 6, 'scott', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 7, 'scott', 1);"); // administer
template.execute("INSERT INTO acl_permission VALUES (null, 8, 'dianne', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 8, 'scott', 2);"); // read
template.execute("INSERT INTO acl_permission VALUES (null, 9, 'scott', 22);"); // read+write+delete
String[] users = {"bill", "bob", "jane"}; // don't want to mess around with consistent sample data
int[] permissions = {1, 2, 22};
for (int i = 10; i < createEntities; i++) {
String user = users[rnd.nextInt(users.length)];
int permission = permissions[rnd.nextInt(permissions.length)];
template.execute("INSERT INTO acl_permission VALUES (null, " + i + ", '" + user + "', " + permission + ");");
String user2 = users[rnd.nextInt(users.length)];
int permission2 = permissions[rnd.nextInt(permissions.length)];
if (!user2.equals(user)) {
template.execute("INSERT INTO acl_permission VALUES (null, " + i + ", '" + user2 + "', " + permission2
+ ");");
}
}
"CREATE TABLE ACL_ENTRY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,ACL_OBJECT_IDENTITY BIGINT NOT NULL,ACE_ORDER INT NOT NULL,SID BIGINT NOT NULL,MASK INTEGER NOT NULL,GRANTING BOOLEAN NOT NULL,AUDIT_SUCCESS BOOLEAN NOT NULL,AUDIT_FAILURE BOOLEAN NOT NULL,CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY,ACE_ORDER),CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID),CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID));");
template.execute(
"CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(50) NOT NULL,ENABLED BOOLEAN NOT NULL);");
@@ -139,6 +99,9 @@ public class DataSourcePopulator implements InitializingBean {
"CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
template.execute(
"CREATE TABLE CONTACTS(ID BIGINT NOT NULL PRIMARY KEY, CONTACT_NAME VARCHAR_IGNORECASE(50) NOT NULL, EMAIL VARCHAR_IGNORECASE(50) NOT NULL)");
/*
Passwords encoded using MD5, NOT in Base64 format, with null as salt
Encoded password for marissa is "koala"
@@ -165,14 +128,100 @@ public class DataSourcePopulator implements InitializingBean {
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
template.execute("INSERT INTO contacts VALUES (1, 'John Smith', 'john@somewhere.com');");
template.execute("INSERT INTO contacts VALUES (2, 'Michael Citizen', 'michael@xyz.com');");
template.execute("INSERT INTO contacts VALUES (3, 'Joe Bloggs', 'joe@demo.com');");
template.execute("INSERT INTO contacts VALUES (4, 'Karen Sutherland', 'karen@sutherland.com');");
template.execute("INSERT INTO contacts VALUES (5, 'Mitchell Howard', 'mitchell@abcdef.com');");
template.execute("INSERT INTO contacts VALUES (6, 'Rose Costas', 'rose@xyz.com');");
template.execute("INSERT INTO contacts VALUES (7, 'Amanda Smith', 'amanda@abcdef.com');");
template.execute("INSERT INTO contacts VALUES (8, 'Cindy Smith', 'cindy@smith.com');");
template.execute("INSERT INTO contacts VALUES (9, 'Jonathan Citizen', 'jonathan@xyz.com');");
for (int i = 10; i < createEntities; i++) {
String[] person = selectPerson();
template.execute("INSERT INTO contacts VALUES (" + i + ", '" + person[2] + "', '" + person[0].toLowerCase()
+ "@" + person[1].toLowerCase() + ".com');");
}
// Create acl_object_identity rows (and also acl_class rows as needed
for (int i = 1; i < createEntities; i++) {
final ObjectIdentity objectIdentity = new ObjectIdentityImpl(Contact.class, new Long(i));
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus arg0) {
MutableAcl acl = mutableAclService.createAcl(objectIdentity);
return null;
}
});
}
// Now grant some permissions
grantPermissions(1, "marissa", BasePermission.ADMINISTRATION);
grantPermissions(2, "marissa", BasePermission.READ);
grantPermissions(3, "marissa", BasePermission.READ);
grantPermissions(3, "marissa", BasePermission.WRITE);
grantPermissions(3, "marissa", BasePermission.DELETE);
grantPermissions(4, "marissa", BasePermission.ADMINISTRATION);
grantPermissions(4, "dianne", BasePermission.ADMINISTRATION);
grantPermissions(4, "scott", BasePermission.READ);
grantPermissions(5, "dianne", BasePermission.ADMINISTRATION);
grantPermissions(5, "dianne", BasePermission.READ);
grantPermissions(6, "dianne", BasePermission.READ);
grantPermissions(6, "dianne", BasePermission.WRITE);
grantPermissions(6, "dianne", BasePermission.DELETE);
grantPermissions(6, "scott", BasePermission.READ);
grantPermissions(7, "scott", BasePermission.ADMINISTRATION);
grantPermissions(8, "dianne", BasePermission.ADMINISTRATION);
grantPermissions(8, "dianne", BasePermission.READ);
grantPermissions(8, "scott", BasePermission.READ);
grantPermissions(9, "scott", BasePermission.ADMINISTRATION);
grantPermissions(9, "scott", BasePermission.READ);
grantPermissions(9, "scott", BasePermission.WRITE);
grantPermissions(9, "scott", BasePermission.DELETE);
// Now expressly change the owner of the first ten contacts
// We have to do this last, because "marissa" owns all of them (doing it sooner would prevent ACL updates)
// Note that ownership has no impact on permissions - they're separate (ownership only allows ACl editing)
changeOwner(5, "dianne");
changeOwner(6, "dianne");
changeOwner(7, "scott");
changeOwner(8, "dianne");
changeOwner(9, "scott");
String[] users = {"bill", "bob", "jane"}; // don't want to mess around with consistent sample data
Permission[] permissions = {BasePermission.ADMINISTRATION, BasePermission.READ, BasePermission.DELETE};
for (int i = 10; i < createEntities; i++) {
String user = users[rnd.nextInt(users.length)];
Permission permission = permissions[rnd.nextInt(permissions.length)];
grantPermissions(i, user, permission);
String user2 = users[rnd.nextInt(users.length)];
Permission permission2 = permissions[rnd.nextInt(permissions.length)];
grantPermissions(i, user2, permission2);
}
SecurityContextHolder.clearContext();
}
private void changeOwner(int contactNumber, String newOwnerUsername) {
AclImpl acl = (AclImpl) mutableAclService.readAclById(new ObjectIdentityImpl(Contact.class,
new Long(contactNumber)));
acl.setOwner(new PrincipalSid(newOwnerUsername));
updateAclInTransaction(acl);
}
public int getCreateEntities() {
return createEntities;
}
public DataSource getDataSource() {
return dataSource;
private void grantPermissions(int contactNumber, String recipientUsername, Permission permission) {
AclImpl acl = (AclImpl) mutableAclService.readAclById(new ObjectIdentityImpl(Contact.class,
new Long(contactNumber)));
acl.insertAce(null, permission, new PrincipalSid(recipientUsername), true);
updateAclInTransaction(acl);
}
private String[] selectPerson() {
@@ -187,6 +236,24 @@ public class DataSourcePopulator implements InitializingBean {
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.template = new JdbcTemplate(dataSource);
}
public void setMutableAclService(MutableAclService mutableAclService) {
this.mutableAclService = mutableAclService;
}
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
this.tt = new TransactionTemplate(platformTransactionManager);
}
private void updateAclInTransaction(final MutableAcl acl) {
tt.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus arg0) {
mutableAclService.updateAcl(acl);
return null;
}
});
}
}
@@ -12,10 +12,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.acl.AclManager;
import org.acegisecurity.acls.AclService;
import org.acegisecurity.acls.Permission;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.acls.sid.Sid;
import org.springframework.beans.factory.InitializingBean;
@@ -44,42 +47,40 @@ import javax.servlet.http.HttpServletResponse;
public class DeletePermissionController implements Controller, InitializingBean {
//~ Instance fields ================================================================================================
private AclManager aclManager;
private AclService aclService;
private ContactManager contactManager;
//~ Methods ========================================================================================================
public void afterPropertiesSet() throws Exception {
Assert.notNull(contactManager, "A ContactManager implementation is required");
Assert.notNull(aclManager, "An aclManager implementation is required");
}
public AclManager getAclManager() {
return aclManager;
}
public ContactManager getContactManager() {
return contactManager;
Assert.notNull(aclService, "An aclService implementation is required");
}
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// <c:param name="sid" value="${acl.sid.principal}"/><c:param name="permission" value="${acl.permission.mask}"/></c:url>">Del</A>
int contactId = RequestUtils.getRequiredIntParameter(request, "contactId");
String recipient = RequestUtils.getRequiredStringParameter(request, "recipient");
String sid = RequestUtils.getRequiredStringParameter(request, "sid");
int mask = RequestUtils.getRequiredIntParameter(request, "permission");
Contact contact = contactManager.getById(new Long(contactId));
contactManager.deletePermission(contact, recipient);
Sid sidObject = new PrincipalSid(sid);
Permission permission = BasePermission.buildFromMask(mask);
contactManager.deletePermission(contact, sidObject, permission);
Map model = new HashMap();
model.put("contact", contact);
model.put("recipient", recipient);
model.put("sid", sidObject);
model.put("permission", permission);
return new ModelAndView("deletePermission", "model", model);
}
public void setAclManager(AclManager aclManager) {
this.aclManager = aclManager;
public void setAclService(AclService aclService) {
this.aclService = aclService;
}
public void setContactManager(ContactManager contact) {
@@ -22,14 +22,14 @@
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
<!-- ACL permission masks used by this application -->
<bean id="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION</value></property>
</bean>
<bean id="org.acegisecurity.acl.basic.SimpleAclEntry.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acl.basic.SimpleAclEntry.READ</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.READ</value></property>
</bean>
<bean id="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acl.basic.SimpleAclEntry.DELETE</value></property>
<bean id="org.acegisecurity.acls.domain.BasePermission.DELETE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="staticField"><value>org.acegisecurity.acls.domain.BasePermission.DELETE</value></property>
</bean>
@@ -37,41 +37,53 @@
<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"/>
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
<bean id="aclContactReadVoter" class="org.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_READ</value></property>
<bean id="aclContactReadVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_READ</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_DELETE</value></property>
<bean id="aclContactDeleteVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_DELETE</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.DELETE"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.DELETE"/>
</list>
</property>
</bean>
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
<bean id="aclContactAdminVoter" class="org.acegisecurity.vote.BasicAclEntryVoter">
<property name="processConfigAttribute"><value>ACL_CONTACT_ADMIN</value></property>
<bean id="aclContactAdminVoter" class="org.acegisecurity.vote.AclEntryVoter">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<value>ACL_CONTACT_ADMIN</value>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
</list>
</constructor-arg>
<property name="processDomainObjectClass"><value>sample.contact.Contact</value></property>
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
</list>
</property>
</bean>
<!-- An access decision manager used by the business objects -->
@@ -89,21 +101,49 @@
<!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
<bean id="aclManager" class="org.acegisecurity.acl.AclProviderManager">
<property name="providers">
<list>
<ref local="basicAclProvider"/>
</list>
</property>
</bean>
<bean id="basicAclProvider" class="org.acegisecurity.acl.basic.BasicAclProvider">
<property name="basicAclDao"><ref local="basicAclExtendedDao"/></property>
</bean>
<bean id="basicAclExtendedDao" class="org.acegisecurity.acl.basic.jdbc.JdbcExtendedDaoImpl">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="aclCache" class="org.acegisecurity.acls.jdbc.EhCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
</property>
<property name="cacheName">
<value>aclCache</value>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="lookupStrategy" class="org.acegisecurity.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="aclCache"/>
<constructor-arg ref="aclAuthorizationStrategy"/>
<constructor-arg>
<bean class="org.acegisecurity.acls.domain.ConsoleAuditLogger"/>
</constructor-arg>
</bean>
<bean id="aclAuthorizationStrategy" class="org.acegisecurity.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
<bean class="org.acegisecurity.GrantedAuthorityImpl">
<constructor-arg value="ROLE_ADMINISTRATOR"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="aclService" class="org.acegisecurity.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource"/>
<constructor-arg ref="lookupStrategy"/>
<constructor-arg ref="aclCache"/>
</bean>
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
@@ -117,28 +157,31 @@
</bean>
<!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
<bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
<bean id="afterAclCollectionRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- Processes AFTER_ACL_READ configuration settings -->
<bean id="afterAclRead" class="org.acegisecurity.afterinvocation.BasicAclEntryAfterInvocationProvider">
<property name="aclManager"><ref local="aclManager"/></property>
<property name="requirePermission">
<list>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.ADMINISTRATION"/>
<ref local="org.acegisecurity.acl.basic.SimpleAclEntry.READ"/>
</list>
</property>
<bean id="afterAclRead" class="org.acegisecurity.afterinvocation.AclEntryAfterInvocationProvider">
<constructor-arg>
<ref bean="aclService"/>
</constructor-arg>
<constructor-arg>
<list>
<ref local="org.acegisecurity.acls.domain.BasePermission.ADMINISTRATION"/>
<ref local="org.acegisecurity.acls.domain.BasePermission.READ"/>
</list>
</constructor-arg>
</bean>
<!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->
<!-- getRandomContact() is public.
@@ -16,7 +16,8 @@
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:mem:contacts</value>
<value>jdbc:hsqldb:mem:test</value>
<!-- <value>jdbc:hsqldb:hsql://localhost/acl</value> -->
</property>
<property name="username">
<value>sa</value>
@@ -46,7 +47,9 @@
</bean>
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
<property name="dataSource"><ref local="dataSource"/></property>
<property name="dataSource" ref="dataSource"/>
<property name="mutableAclService" ref="aclService"/>
<property name="platformTransactionManager" ref="transactionManager"/>
</bean>
<bean id="contactDao" class="sample.contact.ContactDaoSpring">
@@ -66,7 +69,7 @@
<bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
<property name="contactDao"><ref local="contactDao"/></property>
<property name="basicAclExtendedDao"><ref bean="basicAclExtendedDao"/></property>
<property name="mutableAclService"><ref bean="aclService"/></property>
</bean>
</beans>
@@ -29,12 +29,12 @@
<bean id="adminPermissionController" class="sample.contact.AdminPermissionController">
<property name="contactManager"><ref bean="contactManager"/></property>
<property name="aclManager"><ref bean="aclManager"/></property>
<property name="aclService"><ref bean="aclService"/></property>
</bean>
<bean id="deletePermissionController" class="sample.contact.DeletePermissionController">
<property name="contactManager"><ref bean="contactManager"/></property>
<property name="aclManager"><ref bean="aclManager"/></property>
<property name="aclService"><ref bean="aclService"/></property>
</bean>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
@@ -1,4 +1,3 @@
<%@ page import="org.acegisecurity.acl.basic.SimpleAclEntry" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
@@ -11,27 +10,17 @@
</code>
<P>
<table cellpadding=3 border=0>
<c:forEach var="acl" items="${model.acls}">
<c:if test="${acl.class.name eq 'org.acegisecurity.acl.basic.SimpleAclEntry'}">
<c:forEach var="acl" items="${model.acl.entries}">
<tr>
<td>
<code>
<%
SimpleAclEntry simpleAcl = ((SimpleAclEntry) pageContext.getAttribute("acl"));
String permissionBlock = simpleAcl.printPermissionsBlock();
%>
<%= permissionBlock %>
[<c:out value="${acl.mask}"/>]
<c:out value="${acl.recipient}"/>
<c:out value="${acl}"/>
</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>
<A HREF="<c:url value="deletePermission.htm"><c:param name="contactId" value="${model.contact.id}"/><c:param name="sid" value="${acl.sid.principal}"/><c:param name="permission" value="${acl.permission.mask}"/></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>
@@ -1,4 +1,3 @@
<%@ page import="org.acegisecurity.acl.basic.SimpleAclEntry" %>
<%@ include file="/WEB-INF/jsp/include.jsp" %>
<html>
@@ -11,8 +10,11 @@
</code>
<P>
<code>
<c:out value="${model.recipient}"/>
<c:out value="${model.sid}"/>
</code>
<code>
<c:out value="${model.permission}"/>
</code>
<p><a href="<c:url value="index.htm"/>">Manage</a>
</body>
</html>
@@ -18,12 +18,12 @@
<td>
<c:out value="${contact.email}"/>
</td>
<authz:acl domainObject="${contact}" hasPermission="16,1">
<authz:accesscontrollist domainObject="${contact}" hasPermission="8,16">
<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">
</authz:accesscontrollist>
<authz:accesscontrollist domainObject="${contact}" hasPermission="16">
<td><A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</A></td>
</authz:acl>
</authz:accesscontrollist>
</tr>
</c:forEach>
</table>
@@ -1,115 +0,0 @@
package sample.contact;
import java.util.Iterator;
import java.util.List;
import org.acegisecurity.Authentication;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.context.SecurityContextImpl;
import org.acegisecurity.context.SecurityContextHolder;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.test.AbstractTransactionalSpringContextTests;
/**
* Provides simplified access to the <code>ContactManager</code> bean and
* convenience test support methods.
*
* @author David Leal
* @author Ben Alex
*/
public abstract class AbstractContactsSampleTest extends AbstractTransactionalSpringContextTests {
protected ContactManager contactManager;
protected String[] getConfigLocations() {
setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
return new String[] { "applicationContext-common-authorization.xml",
"applicationContext-common-business.xml",
"applicationContext-contacts-test.xml" };
}
/**
* Locates the first <code>Contact</code> of the exact name specified.
*
* <p>
* Uses the {@link ContactManager#getAll()} method.
* </p>
*
* @param id
* Identify of the contact to locate (must be an exact match)
*
* @return the domain or <code>null</code> if not found
*/
protected Contact getContact(String id) {
List contacts = contactManager.getAll();
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().equals(id)) {
return contact;
}
}
return null;
}
protected void assertContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
System.out.println(contacts);
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().toString().equals(id)) {
return;
}
}
fail("List of contacts should have contained: " + id);
}
protected void assertNotContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact domain = (Contact) iter.next();
if (domain.getId().toString().equals(id)) {
fail("List of contact should NOT (but did) contain: " + id);
}
}
}
protected void makeActiveUser(String username) {
String password = "";
if ("marissa".equals(username)) {
password = "koala";
} else if ("dianne".equals(username)) {
password = "emu";
} else if ("scott".equals(username)) {
password = "wombat";
} else if ("peter".equals(username)) {
password = "opal";
}
Authentication authRequest = new UsernamePasswordAuthenticationToken(
username, password);
SecurityContextImpl secureContext = new SecurityContextImpl();
secureContext.setAuthentication(authRequest);
SecurityContextHolder.setContext(secureContext);
}
protected void onTearDownInTransaction() {
destroySecureContext();
}
private static void destroySecureContext() {
SecurityContextHolder.setContext(new SecurityContextImpl());
}
public void setContactManager(ContactManager contactManager) {
this.contactManager = contactManager;
}
}
@@ -12,68 +12,174 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.contact;
import org.acegisecurity.Authentication;
import org.acegisecurity.acls.domain.BasePermission;
import org.acegisecurity.acls.sid.PrincipalSid;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.test.AbstractTransactionalSpringContextTests;
import java.util.Iterator;
import java.util.List;
/**
* Tests {@link
* com.acegitech.dns.domain.DomainManager#findAllDomainsLike(String)}.
* Tests {@link ContactManager}.
*
* @author David Leal
* @author Ben Alex
*/
public class GetAllContactsTests extends AbstractContactsSampleTest {
//~ Methods ================================================================
public class GetAllContactsTests extends AbstractTransactionalSpringContextTests {
//~ Instance fields ================================================================================================
public void testFindAllDomainsLikeAsDianne() {
protected ContactManager contactManager;
//~ Methods ========================================================================================================
protected void assertContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
System.out.println(contacts);
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().toString().equals(id)) {
return;
}
}
fail("List of contacts should have contained: " + id);
}
protected void assertNotContainsContact(String id, List contacts) {
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact domain = (Contact) iter.next();
if (domain.getId().toString().equals(id)) {
fail("List of contact should NOT (but did) contain: " + id);
}
}
}
private static void destroySecureContext() {
SecurityContextHolder.clearContext();
}
protected String[] getConfigLocations() {
setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
return new String[] {
"applicationContext-common-authorization.xml", "applicationContext-common-business.xml",
"applicationContext-contacts-test.xml"
};
}
/**
* Locates the first <code>Contact</code> of the exact name specified.<p>Uses the {@link
* ContactManager#getAll()} method.</p>
*
* @param id Identify of the contact to locate (must be an exact match)
*
* @return the domain or <code>null</code> if not found
*/
protected Contact getContact(String id) {
List contacts = contactManager.getAll();
Iterator iter = contacts.iterator();
while (iter.hasNext()) {
Contact contact = (Contact) iter.next();
if (contact.getId().equals(id)) {
return contact;
}
}
return null;
}
protected void makeActiveUser(String username) {
String password = "";
if ("marissa".equals(username)) {
password = "koala";
} else if ("dianne".equals(username)) {
password = "emu";
} else if ("scott".equals(username)) {
password = "wombat";
} else if ("peter".equals(username)) {
password = "opal";
}
Authentication authRequest = new UsernamePasswordAuthenticationToken(username, password);
SecurityContextHolder.getContext().setAuthentication(authRequest);
}
protected void onTearDownInTransaction() {
destroySecureContext();
}
public void setContactManager(ContactManager contactManager) {
this.contactManager = contactManager;
}
public void testDianne() {
makeActiveUser("dianne"); // has ROLE_USER
List contacts = contactManager.getAll();
assertEquals(4, contacts.size());
assertContainsContact(Long.toString(4), contacts);
assertContainsContact(Long.toString(5), contacts);
assertContainsContact(Long.toString(6), contacts);
assertContainsContact(Long.toString(8), contacts);
assertNotContainsContact(Long.toString(1), contacts);
assertNotContainsContact(Long.toString(2), contacts);
assertNotContainsContact(Long.toString(3), contacts);
}
public void testFindAllDomainsLikeAsMarissa() {
public void testMarissa() {
makeActiveUser("marissa"); // has ROLE_SUPERVISOR
List contacts = contactManager.getAll();
List contacts = contactManager.getAll();
assertEquals(4, contacts.size());
assertContainsContact(Long.toString(1), contacts);
assertContainsContact(Long.toString(2), contacts);
assertContainsContact(Long.toString(3), contacts);
assertContainsContact(Long.toString(4), contacts);
assertNotContainsContact(Long.toString(5), contacts);
assertNotContainsContact(Long.toString(5), contacts);
Contact c1 = contactManager.getById(new Long(4));
contactManager.deletePermission(c1, new PrincipalSid("bob"), BasePermission.ADMINISTRATION);
}
public void testFindAllDomainsLikeAsScott() {
public void testScott() {
makeActiveUser("scott"); // has ROLE_USER
List contacts = contactManager.getAll();
assertEquals(5, contacts.size());
assertEquals(5, contacts.size());
assertContainsContact(Long.toString(4), contacts);
assertContainsContact(Long.toString(6), contacts);
assertContainsContact(Long.toString(7), contacts);
assertContainsContact(Long.toString(8), contacts);
assertContainsContact(Long.toString(9), contacts);
assertNotContainsContact(Long.toString(1), contacts);
assertNotContainsContact(Long.toString(1), contacts);
}
}