Section 7.5. Securing Application Methods

team bbl


7.5. Securing Application Methods

In this lab, you'll learn to use a different kind of security. You'll secure a method on a bean instead of a servlet. This type of security is still declarative, but it's a little more involved.

EJB security works by assigning users roles, giving permissions to those roles, and then assigning permissions to individual methods. In Spring, to use that model, you'll want to secure a method on a bean in the context, instead. In most cases, you'll want to secure the methods on your façade layerin your case, the rentaBike bean.

7.5.1. How do I do that?

Method-based security relies on user roles, just like servlet-based security does (Example 7-23). You have already established two users with different roles in the previous lab.

Example 7-23. RentABikeApp-Servlet.xml
<bean      >    <property name="userMap">       <value>          justin=gehtland,ROLE_USER,ROLE_ADMIN          bruce=tate,ROLE_USER       </value>    </property> </bean>

To establish access rules for methods on a bean, you have to create an instance of ACEGI's MethodSecurityInterceptor (Example 7-24). For this application, you will want to secure methods on the façade layer that controls your data model. The interceptor needs references to a ProviderManager and a DecisionManager, just like the FilterSecurityInterceptor in the previous lab did. Similary, it will have a property called objectDefinitionSource that lists the methods on the beans that need to be secured, and what roles have access to them. For example, all members of ROLE_USER should be able to read data from the database, but only members of ROLE_ADMIN should be able to save, update, or delete.

Example 7-24. RentABikeApp-Servlet.xml
<bean      >    <property name="authenticationManager">       <ref local="authenticationManager"/>    </property>    <property name="accessDecisionManager">       <ref local="httpRequestAccessDecisionManager"/>    </property>    <property name="objectDefinitionSource">       <value>         com.springbook.RentABike.saveBike=ROLE_ADMIN         com.springbook.RentABike.deleteBike=ROLE_ADMIN         com.springbook.RentABike.saveCustomer=ROLE_ADMIN         com.springbook.RentABike.deleteCustomer=ROLE_ADMIN       </value>    </property> </bean>

To wire up the interceptor, you have to create a proxy around the rentaBike controller, just like we did in Chapter 6. First, make sure that your actual BikeStore is configured properly (Example 7-25).

Example 7-25. RentABikeApp-Servlet.xml
<bean  >    <property name="storeName"><value>Bruce's Bikes</value></ property>    <property name="sessionFactory"><ref local="sessionFactory"/></ property>    <property name="transactionManager">       <ref local="transactionManager"/>    </property> </bean>

Then, wrap it in a Spring interceptor, using the MethodSecurityInterceptor as the filter (Example 7-26).

Example 7-26. RentABikeApp-Servlet.xml
<bean      >    <property name="proxyInterfaces">       <value>com.springbook.RentABike</value>    </property>    <property name="interceptorNames">       <list>          <idref local="bikeRentalSecurity"/>          <idref local="rentaBikeTarget"/>       </list>    </property> </bean>

Now, try to sign on as a user belonging to ROLE_ADMIN. Example 7-27 is the log output when you attempt to issue a saveBike command.

Example 7-27. rentabike.log
2004-11-29 10:41:39,906 DEBUG [net.sf.acegisecurity.intercept.AbstractSecurityInterceptor]  - Secure object: Invocation: method=[public abstract void com.springbook.RentABike. saveBike(com.springbook.Bike)] args=[Ljava.lang.Object;@68b9f] target is of class  [com.springbook.HibRentABike]; ConfigAttributes: [ROLE_ADMIN] 2004-11-29 10:41:39,906 DEBUG [net.sf.acegisecurity.providers.ProviderManager]  - Authentication attempt using net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider 2004-11-29 10:41:39,906 DEBUG [org.springframework.web.context.support. XmlWebApplicationContext] - Publishing event in context [XmlWebApplicationContext for  namespace 'rentaBikeApp-servlet']: net.sf.acegisecurity.providers.dao.event.AuthenticationSuccessEvent[source=net.sf. acegisecurity.providers.UsernamePasswordAuthenticationToken@d92c96: Username: justin;  Password: [PROTECTED]; Authenticated: false; Details: 127.0.0.1; Granted Authorities:  ROLE_USER, ROLE_ADMIN] 2004-11-29 10:41:39,906 INFO [net.sf.acegisecurity.providers.dao.event.LoggerListener]  - Authentication success for user: justin; details: 127.0.0.1 ...[call then proceeds as normal]

If you log out and log back in as a user NOT in the ROLE_ADMIN role, Example 7-28 is the log output.

Example 7-28. rentabike.log
2004-11-29 11:04:59,240 DEBUG [net.sf.acegisecurity.intercept.AbstractSecurityInterceptor]  - Secure object: Invocation: method=[public abstract void com.springbook.RentABike.saveBike (com.springbook.Bike)] args=[Ljava.lang.Object;@26bd42] target is of class  [com.springbook.HibRentABike]; ConfigAttributes: [ROLE_ADMIN] 2004-11-29 11:04:59,240 DEBUG [net.sf.acegisecurity.providers.ProviderManager]  - Authentication attempt using net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider 2004-11-29 11:04:59,240 DEBUG [org.springframework.web.context.support. XmlWebApplicationContext] - Publishing event in context [XmlWebApplicationContext for  namespace 'rentaBikeApp-servlet']: net.sf.acegisecurity.providers.dao.event. AuthenticationSuccessEvent[source=net.sf.acegisecurity.providers. UsernamePasswordAuthenticationToken@c91c22: Username: bruce; Password: [PROTECTED];  Authenticated: false; Details: 127.0.0.1; Granted Authorities: ROLE_USER] 2004-11-29 11:04:59,241 INFO [net.sf.acegisecurity.providers.dao.event.LoggerListener]  - Authentication success for user: bruce; details: 127.0.0.1 2004-11-29 11:04:59,241 DEBUG [org.springframework.web.context.support. XmlWebApplicationContext] - Publishing event in context [Root XmlWebApplicationContext]: net.sf.acegisecurity.providers.dao.event.AuthenticationSuccessEvent[source=net.sf. acegisecurity.providers.UsernamePasswordAuthenticationToken@c91c22: Username: bruce;  Password: [PROTECTED]; Authenticated: false; Details: 127.0.0.1; Granted Authorities:  ROLE_USER] 2004-11-29 11:04:59,241 INFO [net.sf.acegisecurity.providers.dao.event.LoggerListener]  - Authentication success for user: bruce; details: 127.0.0.1 2004-11-29 11:04:59,241 DEBUG [net.sf.acegisecurity.intercept.AbstractSecurityInterceptor] - Authenticated: net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken@537945: Username: bruce; Password: [PROTECTED]; Authenticated: true; Details: 127.0.0.1; Granted  Authorities: ROLE_USER 2004-11-29 11:04:59,241 ERROR [org.springframework.web.servlet.DispatcherServlet] -  Could not complete request net.sf.acegisecurity.AccessDeniedException: Access is denied.     at net.sf.acegisecurity.vote.AffirmativeBased.decide(AffirmativeBased.java:86) ETC. 2004-11-29 11:04:59,243 DEBUG [org.springframework.web.context.support. XmlWebApplicationContext] - Publishing event in context [XmlWebApplicationContext for  namespace 'rentaBikeApp-servlet']: RequestHandledEvent: url=[/rentabike/editBike.htm];  time=[5ms]; client=[127.0.0.1]; method=[POST]; servlet=[rentaBikeApp]; session= [029AB8AD12ED146A4356817166C38083]; user=[null]; status=[failed: net.sf.acegisecurity. AccessDeniedException: Access is denied.] 2004-11-29 11:04:59,243 DEBUG [org.springframework.web.context.support. XmlWebApplicationContext] - Publishing event in context [Root XmlWebApplicationContext]:  RequestHandledEvent: url=[/rentabike/editBike.htm]; time=[5ms]; client=[127.0.0.1];  method=[POST]; servlet=[rentaBikeApp]; session=[029AB8AD12ED146A4356817166C38083];  user=[null]; status=[failed: net.sf.acegisecurity.AccessDeniedException: Access is denied.] 2004-11-29 11:04:59,243 DEBUG [net.sf.acegisecurity.intercept.web. SecurityEnforcementFilter] - Access is denied - sending back forbidden response 2004-11-29 11:04:59,243 DEBUG [net.sf.acegisecurity.ui.AbstractIntegrationFilter] -  Updating container with new Authentication object, and then removing Authentication  from ContextHolder

7.5.2. What just happened?

The ACEGI model uses interceptors. These interceptors map credentials (or roles) onto an individual user when the user authenticates. ACEGI stores this information in its authentication engine, and lets you, or an interceptor, query this information.

Next, ACEGI stores a map of permissions on each role. Then, when you proxy an interface, you specify what credentials are required to do a particular thing, like fire a method. Like the other services in this chapter, these work declaratively.

7.5.3. What about...

...instance-based security? EJB security often breaks down because guarding an individual method is not enough. You don't care whether a manager wants to retrieve invoices. You care which invoices the manager wants to retrieve. He should only have access to the invoices for employees in his department.

ACEGI provides instance-based security. You can attach ACLs (access control lists) to individual instances, just as you attached permissions to roles. ACEGI provides a mapping mechanism to do this. You can assign AclEntries to domain instances, then use an AclManager to look up AclEntries from a given domain instance. AccessDecisionManagers then decide if the current user has appropriate permissions based on the AclEntries.

    team bbl



    Spring. A developer's Notebook
    Spring: A Developers Notebook
    ISBN: 0596009100
    EAN: 2147483647
    Year: 2005
    Pages: 90

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net