Acegi Security System for Spring Framework
Part 2 Securing Method Invocation
Outline
Intro Case Study Business Interface Business Implementation Servlet Controller Protecting Business Method Proxying Business Object Conclusion
Introduction to Acegi
Acegi ++
Acegi Security System for Spring
[Link]
Security control in various granularity
Securing URL Securing Method Invocation Securing Object Instance
Non-invasive architecture
Servlet Filter based
Modular Architecture
Pluggable ACL backend Pluggable authentication mechanism Integration with Application Server
Alternatives
Seraph: [Link] jSai - Servlet Security : [Link] Gabriel : [Link] JOSSO : [Link] Kasai: [Link] jPAM : [Link] OpenSAML : [Link] JAAS Custom Implementation
Acegi and Spring
Acegi use Springs Bean Proxy to intercept method invocation Acegi supports AspectJs Join Point (requires bytecode manipulation by AspectJ compiler) AspectJs Join Point can be configured via Spring as well
Security Granularity
URL authorization
[Link] -> for public [Link] -> for authorized user
Method Invocation
public void getData() -> all user public void modifyData() -> supervisor only
Object instance
[Link]() < $100 -> all user [Link]() > $100 -> supervisor only [Link]() == endy -> account mgr only
Non-invasive architecture
Use proxy to intercept method invocation and apply security constraints Business interface can be clean, not cluttered with security logic Users of Springs declarative transaction should find security interception familiar
Convoluted Business Interface
Avoid this :
public void approve(Order o, User u) throws IllegalAccessException { if ([Link]() > 100) { if ()) { throw new IllegalAccessException(); } } [Link](approved); }
Clean Business Interface
Should be like this :
public void approve(Order o) { [Link](approved); }
Case Study
We will secure method invocation User can create Purchase Order
public void create(PurchaseOrder po)
Supervisor can approve Purchase Order
public void approve(PurchaseOrder po)
These requirement to be implemented declaratively
Business Classes
PurchaseOrder
Simple JavaBean
BusinessFacade
Interface for business methods
BusinessFacadeInMemoryImpl
Simple implementation of BusinessFacade Store PurchaseOrder objects in HashMap
[Link]
public class PurchaseOrder { private String description; private String type; private double value; private String status = "posted"; // getter and setter code // not displayed }
[Link]
public interface BusinessFacade { public void createPurchaseOrder (PurchaseOrder po); public void approvePurchaseOrder (PurchaseOrder po); public PurchaseOrder getPurchaseOrder (String description); public List getAllPurchaseOrder (); }
[Link]
public class BusinessFacadeInMemoryImpl implements BusinessFacade { private Map purchaseOrders = new HashMap(); public BusinessFacadeInMemoryImpl() { // initialize some sample data } public void createPurchaseOrder(PurchaseOrder po) { [Link]([Link](), po); } public void approvePurchaseOrder(PurchaseOrder po) { [Link](po); PurchaseOrder px = (PurchaseOrder) [Link]([Link]()); if (px == null) return; [Link]("approved"); } public List getAllPurchaseOrder() { Iterator it = [Link]().iterator(); ArrayList result = new ArrayList(); while([Link]()) { [Link]([Link]([Link]())); } return result; } public PurchaseOrder getPurchaseOrder(String description) { return (PurchaseOrder) [Link](description); } }
Servlet Controller
LoginController
Display login form Do not check username and password, as it has been handled by Acegi
LogoutController
Invalidate session and redirect to default page
ListController
Invoke [Link] Render template ([Link])
Create Controller
Display [Link] page (default) Invoke [Link] (upon form submission)
ApproveController
Display [Link]
ApproveProcessController
Invoke [Link]
[Link]
public class ListController implements Controller { private BusinessFacade businessFacade; public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse res) throws Exception { List allPurchaseOrders = [Link](); Map model = new HashMap(); [Link]("allOrders", allPurchaseOrders); return new ModelAndView("list","allOrders", allPurchaseOrders); } public void setBusinessFacade(BusinessFacade businessFacade) { [Link] = businessFacade; } }
[Link]
String desc = [Link]("description"); String value = [Link]("value"); String type = [Link]("type"); PurchaseOrder po = new PurchaseOrder(); [Link](desc); [Link]([Link](value)); [Link](type); [Link](po);
[Link]
PurchaseOrder po = [Link](desc); if (po == null) { [Link]("[Link]"); return null; } [Link](po);
Protecting Business Methods
<bean id="businessMethodSecurity" class="[Link]. [Link]"> <property name="authenticationManager"> <ref bean="authenticationManager"/> </property> <property name="accessDecisionManager"> <ref local="businessAccessDecisionManager"/> </property> <property name="objectDefinitionSource"> <value> [Link]*=ROLE_SUPERVISOR [Link]*=ROLE_USER </value> </property> </bean>
businessAccessDecisionManager
<bean id="businessAccessDecisionManager" class="[Link]. [Link]"> <property name="allowIfAllAbstainDecisions"> <value>false</value> </property> <property name="decisionVoters"> <list> <ref bean="roleVoter"/> </list> </property> </bean>
Proxying Business Object
<bean id="businessFacade" class="[Link]. [Link]"> <property name="proxyInterfaces"> <value> [Link] </value> </property> <property name="interceptorNames"> <list> <idref bean="businessMethodSecurity"/> <idref local="businessFacadeTarget"/> </list> </property> </bean> <bean id="businessFacadeTarget" class="BusinessFacadeInMemoryImpl"/>
Conclusion
Acegi can protect method invocation transparently (no modification in business code) Method interception is made possible using Springs bean proxy mechanism (similar to transaction proxy) As alternative to Springs proxy, we can use AspectJ join point (need AspectJ compiler)
Thank you
Endy Muhardin [Link]
last updated : 20050521