SEC-1023: Add hasPermission() support to SecurityExpressionRoot
http://jira.springframework.org/browse/SEC-1023. hasPermission() now delegates to a PermissionEvaluator interface, with a default implementation provided by the Acl module. The contacts sample now uses expressions on the ContactManager interface. The permission-evaluator element on global-method-security can be used to set the instance to an AclPermissionEvaluator. If not set, all hasPermission() expressions will evaluate to 'false'.
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
package sample.contact;
|
||||
|
||||
import org.springframework.security.acl.basic.SimpleAclEntry;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
|
||||
|
||||
/**
|
||||
@@ -27,7 +27,7 @@ public class AddPermission {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
public Contact contact;
|
||||
public Integer permission = new Integer(SimpleAclEntry.READ);
|
||||
public Integer permission = BasePermission.READ.getMask();
|
||||
public String recipient;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@@ -26,7 +26,7 @@ import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.validation.BindException;
|
||||
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.SimpleFormController;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
@@ -67,7 +67,7 @@ public class AddPermissionController extends SimpleFormController implements Ini
|
||||
|
||||
protected Object formBackingObject(HttpServletRequest request)
|
||||
throws Exception {
|
||||
int contactId = RequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
int contactId = ServletRequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
|
||||
Contact contact = contactManager.getById(new Long(contactId));
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
@@ -57,7 +57,7 @@ public class AdminPermissionController implements Controller, InitializingBean {
|
||||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
int id = RequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
int id = ServletRequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
|
||||
Contact contact = contactManager.getById(new Long(id));
|
||||
Acl acl = aclService.readAclById(new ObjectIdentityImpl(contact));
|
||||
|
||||
@@ -36,8 +36,9 @@ import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Demonstrates accessing the {@link ContactManager} via remoting protocols.<P>Based on Spring's JPetStore sample,
|
||||
* written by Juergen Hoeller.</p>
|
||||
* Demonstrates accessing the {@link ContactManager} via remoting protocols.
|
||||
* <p>
|
||||
* Based on Spring's JPetStore sample, written by Juergen Hoeller.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
|
||||
@@ -43,8 +43,6 @@ public class Contact implements Serializable {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return Returns the email.
|
||||
*/
|
||||
public String getEmail() {
|
||||
@@ -52,8 +50,6 @@ public class Contact implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
@@ -61,8 +57,6 @@ public class Contact implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
@@ -70,8 +64,6 @@ public class Contact implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @param email The email to set.
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
@@ -83,8 +75,6 @@ public class Contact implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
|
||||
@@ -16,6 +16,8 @@ package sample.contact;
|
||||
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.expression.annotation.PostFilter;
|
||||
import org.springframework.security.expression.annotation.PreAuthorize;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -28,19 +30,28 @@ import java.util.List;
|
||||
*/
|
||||
public interface ContactManager {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, admin)")
|
||||
public void addPermission(Contact contact, Sid recipient, Permission permission);
|
||||
|
||||
public void create(Contact contact);
|
||||
|
||||
public void delete(Contact contact);
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, admin)")
|
||||
public void deletePermission(Contact contact, Sid recipient, Permission permission);
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public void create(Contact contact);
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, 'delete') or hasPermission(#contact, admin)")
|
||||
public void delete(Contact contact);
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, admin)")
|
||||
public List getAll();
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public List getAllRecipients();
|
||||
|
||||
@PreAuthorize(
|
||||
"hasPermission(#id, 'sample.contact.Contact', read) or " +
|
||||
"hasPermission(#id, 'sample.contact.Contact', admin)")
|
||||
public Contact getById(Long id);
|
||||
|
||||
public Contact getRandomContact();
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
@@ -47,6 +48,7 @@ import java.util.Random;
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@Transactional
|
||||
public class ContactManagerBackend extends ApplicationObjectSupport implements ContactManager, InitializingBean {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@@ -124,6 +126,7 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly=true)
|
||||
public List getAll() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning all contacts");
|
||||
@@ -132,6 +135,7 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
||||
return contactDao.findAll();
|
||||
}
|
||||
|
||||
@Transactional(readOnly=true)
|
||||
public List getAllRecipients() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning all recipients");
|
||||
@@ -142,6 +146,7 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
||||
return list;
|
||||
}
|
||||
|
||||
@Transactional(readOnly=true)
|
||||
public Contact getById(Long id) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning contact with id: " + id);
|
||||
@@ -152,9 +157,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
||||
|
||||
/**
|
||||
* This is a public method.
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
@Transactional(readOnly=true)
|
||||
public Contact getRandomContact() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning random contact");
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
@@ -60,9 +60,9 @@ public class DeletePermissionController implements Controller, InitializingBean
|
||||
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 sid = RequestUtils.getRequiredStringParameter(request, "sid");
|
||||
int mask = RequestUtils.getRequiredIntParameter(request, "permission");
|
||||
int contactId = ServletRequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
String sid = ServletRequestUtils.getRequiredStringParameter(request, "sid");
|
||||
int mask = ServletRequestUtils.getRequiredIntParameter(request, "permission");
|
||||
|
||||
Contact contact = contactManager.getById(new Long(contactId));
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class PublicIndexController implements Controller, InitializingBean {
|
||||
}
|
||||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
throws ServletException, IOException {
|
||||
Contact rnd = contactManager.getRandomContact();
|
||||
|
||||
return new ModelAndView("hello", "contact", rnd);
|
||||
|
||||
@@ -17,6 +17,11 @@ package sample.contact;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.expression.PermissionEvaluator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@@ -35,38 +40,55 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Controller for secure index page.
|
||||
* <p>
|
||||
* This controller displays a list of all the contacts for which the current user has read or admin permissions.
|
||||
* It makes a call to {@link ContactManager#getAll()} which automatically filters the returned list using Spring
|
||||
* Security's ACL mechanism (see the expression annotations on this interface for the details).
|
||||
* <p>
|
||||
* In addition to rendering the list of contacts, the view will also include a "Del" or "Admin" link beside the
|
||||
* contact, depending on whether the user has the corresponding permissions (admin permission is assumed to imply
|
||||
* delete here). This information is stored in the model using the injected {@link PermissionEvaluator} instance.
|
||||
* The implementation should be an instance of {@link AclPermissionEvaluator} or one which is compatible with Spring
|
||||
* Security's ACL module.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecureIndexController implements Controller, InitializingBean {
|
||||
private final static Permission[] HAS_DELETE = new Permission[] {BasePermission.DELETE, BasePermission.ADMINISTRATION};
|
||||
private final static Permission[] HAS_ADMIN = new Permission[] {BasePermission.ADMINISTRATION};
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private ContactManager contactManager;
|
||||
private PermissionEvaluator permissionEvaluator;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(contactManager, "A ContactManager implementation is required");
|
||||
}
|
||||
|
||||
public ContactManager getContactManager() {
|
||||
return contactManager;
|
||||
Assert.notNull(permissionEvaluator, "A PermissionEvaluator implementation is required");
|
||||
}
|
||||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
List myContactsList = contactManager.getAll();
|
||||
Contact[] myContacts;
|
||||
throws ServletException, IOException {
|
||||
List<Contact> myContactsList = contactManager.getAll();
|
||||
Map<Contact,Boolean> hasDelete = new HashMap<Contact,Boolean>(myContactsList.size());
|
||||
Map<Contact,Boolean> hasAdmin = new HashMap<Contact,Boolean>(myContactsList.size());
|
||||
|
||||
if (myContactsList.size() == 0) {
|
||||
myContacts = null;
|
||||
} else {
|
||||
myContacts = (Contact[]) myContactsList.toArray(new Contact[] {});
|
||||
Authentication user = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
for (Contact contact : myContactsList) {
|
||||
hasDelete.put(contact,
|
||||
permissionEvaluator.hasPermission(user, contact, HAS_DELETE) ? Boolean.TRUE : Boolean.FALSE);
|
||||
hasAdmin.put(contact,
|
||||
permissionEvaluator.hasPermission(user, contact, HAS_ADMIN) ? Boolean.TRUE : Boolean.FALSE);
|
||||
}
|
||||
|
||||
Map model = new HashMap();
|
||||
model.put("contacts", myContacts);
|
||||
model.put("contacts", myContactsList);
|
||||
model.put("hasDeletePermission", hasDelete);
|
||||
model.put("hasAdminPermission", hasAdmin);
|
||||
|
||||
return new ModelAndView("index", "model", model);
|
||||
}
|
||||
@@ -74,4 +96,8 @@ public class SecureIndexController implements Controller, InitializingBean {
|
||||
public void setContactManager(ContactManager contact) {
|
||||
this.contactManager = contact;
|
||||
}
|
||||
|
||||
public void setPermissionEvaluator(PermissionEvaluator pe) {
|
||||
this.permissionEvaluator = pe;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,77 +14,7 @@
|
||||
- $Id$
|
||||
-->
|
||||
|
||||
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
|
||||
|
||||
<!-- ACL permission masks used by this application -->
|
||||
<bean id="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"
|
||||
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
|
||||
<property name="staticField" value="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
</bean>
|
||||
<bean id="org.springframework.security.acls.domain.BasePermission.READ"
|
||||
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
|
||||
<property name="staticField" value="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</bean>
|
||||
<bean id="org.springframework.security.acls.domain.BasePermission.DELETE"
|
||||
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
|
||||
<property name="staticField" value="org.springframework.security.acls.domain.BasePermission.DELETE"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision voter that reads ROLE_* configuration settings -->
|
||||
<bean id="roleVoter" class="org.springframework.security.vote.RoleVoter"/>
|
||||
|
||||
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
|
||||
<bean id="aclContactReadVoter" class="org.springframework.security.vote.AclEntryVoter">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg value="ACL_CONTACT_READ"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="processDomainObjectClass" value="sample.contact.Contact"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
|
||||
<bean id="aclContactDeleteVoter" class="org.springframework.security.vote.AclEntryVoter">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg value="ACL_CONTACT_DELETE"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.DELETE"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="processDomainObjectClass" value="sample.contact.Contact"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
|
||||
<bean id="aclContactAdminVoter" class="org.springframework.security.vote.AclEntryVoter">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg value="ACL_CONTACT_ADMIN"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="processDomainObjectClass" value="sample.contact.Contact"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision manager used by the business objects -->
|
||||
<bean id="businessAccessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
|
||||
<property name="allowIfAllAbstainDecisions" value="false"/>
|
||||
<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 ========= -->
|
||||
<!-- ========= ACL SERVICE DEFINITIONS ========= -->
|
||||
|
||||
<bean id="aclCache" class="org.springframework.security.acls.jdbc.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
@@ -128,38 +58,4 @@
|
||||
<constructor-arg ref="aclCache"/>
|
||||
</bean>
|
||||
|
||||
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
|
||||
|
||||
<bean id="afterInvocationManager" class="org.springframework.security.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="org.springframework.security.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<!-- Processes AFTER_ACL_READ configuration settings -->
|
||||
<bean id="afterAclRead" class="org.springframework.security.afterinvocation.AclEntryAfterInvocationProvider">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
-->
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:sec="http://www.springframework.org/schema/security"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
@@ -26,38 +26,31 @@
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven transaction-manager="transactionManager" />
|
||||
<!--
|
||||
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
<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>
|
||||
|
||||
<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="dataSource"/>
|
||||
<property name="mutableAclService" ref="aclService"/>
|
||||
<property name="platformTransactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces" value="sample.contact.ContactManager"/>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<idref local="transactionInterceptor"/>
|
||||
<idref local="contactManagerTarget"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
|
||||
<bean id="contactManager" class="sample.contact.ContactManagerBackend">
|
||||
<!--
|
||||
<sec:intercept-methods access-decision-manager-ref="businessAccessDecisionManager">
|
||||
<sec:protect method="sample.contact.ContactManager.create" access="ROLE_USER"/>
|
||||
<sec:protect method="sample.contact.ContactManager.getAllRecipients" access="ROLE_USER"/>
|
||||
@@ -67,6 +60,7 @@
|
||||
<sec:protect method="sample.contact.ContactManager.deletePermission" access="ACL_CONTACT_ADMIN"/>
|
||||
<sec:protect method="sample.contact.ContactManager.addPermission" access="ACL_CONTACT_ADMIN"/>
|
||||
</sec:intercept-methods>
|
||||
-->
|
||||
<property name="contactDao">
|
||||
<bean class="sample.contact.ContactDaoSpring">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
|
||||
@@ -11,15 +11,18 @@
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd">
|
||||
|
||||
<global-method-security expression-annotations="enabled">
|
||||
<permission-evaluator ref="permissionEvaluator"/>
|
||||
</global-method-security>
|
||||
|
||||
<http auto-config="true" realm="Contacts Realm">
|
||||
<intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/hello.htm" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/switchuser.jsp" access="ROLE_SUPERVISOR"/>
|
||||
<intercept-url pattern="/j_spring_security_switch_user" access="ROLE_SUPERVISOR"/>
|
||||
<intercept-url pattern="/**" access="ROLE_USER"/>
|
||||
@@ -28,20 +31,24 @@
|
||||
<logout logout-success-url="/index.jsp"/>
|
||||
</http>
|
||||
|
||||
<authentication-provider>
|
||||
<authentication-provider>
|
||||
<password-encoder hash="md5"/>
|
||||
<jdbc-user-service data-source-ref="dataSource"/>
|
||||
</authentication-provider>
|
||||
</authentication-provider>
|
||||
|
||||
<!-- Automatically receives AuthenticationEvent messages -->
|
||||
<b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
|
||||
<!-- Automatically receives AuthenticationEvent messages -->
|
||||
<b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
|
||||
|
||||
<!-- Filter used to switch the user context. Note: the switch and exit url must be secured
|
||||
<!-- 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 'rod' has ROLE_SUPERVISOR that can switch to regular ROLE_USER(s) -->
|
||||
<b:bean id="switchUserProcessingFilter" class="org.springframework.security.ui.switchuser.SwitchUserProcessingFilter" autowire="byType">
|
||||
<custom-filter position="SWITCH_USER_FILTER"/>
|
||||
<!-- In this example 'rod' has ROLE_SUPERVISOR that can switch to regular ROLE_USER(s) -->
|
||||
<b:bean id="switchUserProcessingFilter" class="org.springframework.security.ui.switchuser.SwitchUserProcessingFilter" autowire="byType">
|
||||
<custom-filter position="SWITCH_USER_FILTER"/>
|
||||
<b:property name="targetUrl" value="/secure/index.htm"/>
|
||||
</b:bean>
|
||||
</b:bean>
|
||||
|
||||
<b:bean id="permissionEvaluator" class="org.springframework.security.acls.AclPermissionEvaluator">
|
||||
<b:constructor-arg ref="aclService" />
|
||||
</b:bean>
|
||||
|
||||
</b:beans>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<beans>
|
||||
|
||||
<!-- ========================== WEB DEFINITIONS ======================= -->
|
||||
<!-- ========================== WEB DEFINITIONS ======================= -->
|
||||
|
||||
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basename" value="messages"/>
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<bean id="secureIndexController" class="sample.contact.SecureIndexController">
|
||||
<property name="contactManager" ref="contactManager"/>
|
||||
<property name="permissionEvaluator" ref="permissionEvaluator" />
|
||||
</bean>
|
||||
|
||||
<bean id="secureDeleteController" class="sample.contact.DeleteController">
|
||||
@@ -75,9 +76,9 @@
|
||||
<property name="contactManager" ref="contactManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="prefix" value="/WEB-INF/jsp/"/>
|
||||
<property name="suffix" value=".jsp"/>
|
||||
</bean>
|
||||
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="prefix" value="/WEB-INF/jsp/"/>
|
||||
<property name="suffix" value=".jsp"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<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}">
|
||||
<c:forEach var="contact" items="${model.contacts}" >
|
||||
<tr>
|
||||
<td>
|
||||
<c:out value="${contact.id}"/>
|
||||
@@ -18,12 +18,12 @@
|
||||
<td>
|
||||
<c:out value="${contact.email}"/>
|
||||
</td>
|
||||
<security: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>
|
||||
</security:accesscontrollist>
|
||||
<security: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>
|
||||
</security:accesscontrollist>
|
||||
<c:if test="${model.hasDeletePermission[contact]}">
|
||||
<td><a href="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</a></td>
|
||||
</c:if>
|
||||
<c:if test="${model.hasAdminPermission[contact]}">
|
||||
<td><a href="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</a></td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
||||
@@ -14,22 +14,24 @@
|
||||
*/
|
||||
package sample.contact;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
|
||||
import org.springframework.test.AbstractTransactionalSpringContextTests;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link ContactManager}.
|
||||
@@ -37,9 +39,15 @@ import java.util.List;
|
||||
* @author David Leal
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class GetAllContactsTests extends AbstractTransactionalSpringContextTests {
|
||||
@ContextConfiguration(locations={
|
||||
"/applicationContext-common-authorization.xml",
|
||||
"/applicationContext-common-business.xml",
|
||||
"/applicationContext-contacts-test.xml"})
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class GetAllContactsTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@Autowired
|
||||
protected ContactManager contactManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
@@ -59,7 +67,7 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
||||
fail("List of contacts should have contained: " + id);
|
||||
}
|
||||
|
||||
protected void assertNotContainsContact(String id, List contacts) {
|
||||
void assertDoestNotContainContact(String id, List contacts) {
|
||||
Iterator iter = contacts.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
@@ -71,15 +79,6 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -120,14 +119,12 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
||||
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
||||
}
|
||||
|
||||
protected void onTearDownInTransaction() {
|
||||
@After
|
||||
public void onTearDownInTransaction() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void setContactManager(ContactManager contactManager) {
|
||||
this.contactManager = contactManager;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDianne() {
|
||||
makeActiveUser("dianne"); // has ROLE_USER
|
||||
|
||||
@@ -139,11 +136,12 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
||||
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);
|
||||
assertDoestNotContainContact(Long.toString(1), contacts);
|
||||
assertDoestNotContainContact(Long.toString(2), contacts);
|
||||
assertDoestNotContainContact(Long.toString(3), contacts);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testrod() {
|
||||
makeActiveUser("rod"); // has ROLE_SUPERVISOR
|
||||
|
||||
@@ -156,13 +154,14 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
||||
assertContainsContact(Long.toString(3), contacts);
|
||||
assertContainsContact(Long.toString(4), contacts);
|
||||
|
||||
assertNotContainsContact(Long.toString(5), contacts);
|
||||
assertDoestNotContainContact(Long.toString(5), contacts);
|
||||
|
||||
Contact c1 = contactManager.getById(new Long(4));
|
||||
|
||||
contactManager.deletePermission(c1, new PrincipalSid("bob"), BasePermission.ADMINISTRATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScott() {
|
||||
makeActiveUser("scott"); // has ROLE_USER
|
||||
|
||||
@@ -176,6 +175,6 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
||||
assertContainsContact(Long.toString(8), contacts);
|
||||
assertContainsContact(Long.toString(9), contacts);
|
||||
|
||||
assertNotContainsContact(Long.toString(1), contacts);
|
||||
assertDoestNotContainContact(Long.toString(1), contacts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
<b:beans xmlns="http://www.springframework.org/schema/security"
|
||||
xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd">
|
||||
|
||||
<global-method-security expression-annotations="enabled">
|
||||
<permission-evaluator ref="permissionEvaluator"/>
|
||||
</global-method-security>
|
||||
|
||||
<!-- ======================== AUTHENTICATION ======================= -->
|
||||
|
||||
@@ -21,8 +24,8 @@
|
||||
<jdbc-user-service data-source-ref="dataSource"/>
|
||||
</authentication-provider>
|
||||
|
||||
|
||||
<!-- Automatically receives AuthenticationEvent messages -->
|
||||
<b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
|
||||
<b:bean id="permissionEvaluator" class="org.springframework.security.acls.AclPermissionEvaluator">
|
||||
<b:constructor-arg ref="aclService" />
|
||||
</b:bean>
|
||||
|
||||
</b:beans>
|
||||
|
||||
Reference in New Issue
Block a user