Raible's Wiki

Raible Designs
Wiki Home
News
Recent Changes

AppFuse

Homepage
  - Korean
  - Chinese
  - Italian
  - Japanese

QuickStart Guide
  - Chinese
  - French
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish
  - Japanese

User Guide
  - Korean
  - Chinese

Tutorials
  - Chinese
  - German
  - Italian
  - Korean
  - Portuguese
  - Spanish

FAQ
  - Korean

Latest Downloads

Other Applications

Struts Resume
Security Example
Struts Menu

Set your name in
UserPreferences


Referenced by
AppFuseSecurityMetho...




JSPWiki v2.2.33

[RSS]


Hide Menu

AppFuseSecurityMethods2


Difference between version 10 and version 1:

At line 1 changed 1 line.
In part one of this tutorial we got basic Method Invocation security working. But there still remains some holes in the security of our User object at the service level. For example if someone could get the controller to run UserManager.saveUser() on someone other than themselves, there is nothing at the service level to stop them.
In [Part I|AppFuseSecurityMethods] of this tutorial we got basic Method Invocation security working. But there still remains some holes in the security of our {{User}} object at the service level. For example if someone could get the controller to run {{UserManager.saveUser()}} on someone other than themselves, there is nothing at the service level to stop them.
At line 14 changed 1 line.
!! Prerequisites [0]
!! Prerequisites [#0]
At line 17 changed 1 line.
!! Add UserManager.updateUser() method [1]
!! Add UserManager.updateUser() method [#1]
Because we want new users to be able to create a new account, and we want existing users (who are not {{admin}}'s) to only be able to update their own User object we need two separate methods in our {{UserManager}} to handle this. One method, {{updateUser()}}, will be secured and the other, {{saveUser()}} will not.
%%note __NOTE:__ These methods should probably be {{updateUser()}} and {{createUser()}}, but I wanted to change as little as possible to get this working. You should be able to figure out how to make this change after understanding this tutorial.%%
At line 19 changed 1 line.
!! Modify txProxyTemplate configuration [2]
We need to add or modify the following code to these classes:
{{UserManagerTest.testSaveUser()}} change:
{{{
userManager.saveUser(user);
}}}
to:
{{{
userManager.updateUser(user);
}}}
At line 21 changed 1 line.
!! Create the OwnerVoter [3]
{{UserManager}} add:
{{{
public void updateUser(User user) throws UserExistsException;
}}}
At line 23 changed 1 line.
!! Modify userManagerSecurity configuration [4]
{{UserManagerImpl}} add:
{{{
public void updateUser(User user) throws UserExistsException {
saveUser(user);
}
}}}
At line 25 changed 1 line.
!! Test All [5]
%%note __NOTE:__ These manager methods should probably be smarter by making {{saveUser()}} only be able to save a new user and {{updateUser()}} only update an existing user, but for now this is what we have.%%
{{UserAction.save()}} change:
{{{
mgr.saveUser(user);
}}}
to:
{{{
mgr.updateUser(user);
}}}
!! Modify {{txProxyTemplate}} configuration [#2]
Because we are now saving a record with a method that does not fit the pattern {{save*}} we need to update the {{txProxyTemplate}} bean in {{applicationContext-service.xml}}.
{{{
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
}}}
!! Create the {{OwnerVoter}} [#3]
I thought this would be appropriate to place in an {{org.appfuse.security}} package within {{src/service}}. You can download [OwnerVoter here|http://raibledesigns.com/wiki/attach?page=AppFuseSecurityMethods2%2FOwnerVoter.java].
!! Modify {{userManagerSecurity}} configuration [#4]
We need to define a few more beans and modify the bean definition of {{userManagerSecurity}} in {{applicationContext-security.xml}}.
The {{OwnerVoter}} only works on Method Invocation security, so we now need to have a seperate {{accessDecisionManager}} for {{userManagerSecurity}} bean from the one being used for URI security.
{{{
<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="userOwnerVoter"/>
<ref local="usernameStringOwnerVoter"/>
</list>
</property>
</bean>
}}}
You will notice that {{businessAccessDecisionManager}} now has references to a couple of new beans based on {{OwnerVoter}}. The first one looks for methods that have an argument of type {{User}} and grants access when the authenticated user's username matches {{User.getUsername()}} on that object.
{{{
<bean id="userOwnerVoter" class="org.appfuse.security.OwnerVoter">
<property name="processConfigAttribute">
<value>OWNER_USER_EQUALS</value></property>
<property name="processDomainObjectClass">
<value>org.appfuse.model.User</value></property>
<property name="internalMethod">
<value>getUsername</value></property>
</bean>
}}}
The second bean is for methods that are passed a username {{String}} rather than the entire object. In this case the string is compared to the authenticated user's username
{{{
<bean id="usernameStringOwnerVoter" class="org.appfuse.security.OwnerVoter">
<property name="processConfigAttribute">
<value>OWNER_STRING_EQUALS</value></property>
<property name="processDomainObjectClass">
<value>java.lang.String</value></property>
<property name="internalMethod">
<value>toString</value></property>
</bean>
}}}
Next we need to update the {{userManagerSecurity}} defintion to utilize the {{OwnerVoter}}'s we just defined.
{{{
<bean id="userManagerSecurity" class="net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager"><ref bean="authenticationManager"/></property>
<property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
<property name="objectDefinitionSource">
<value>
org.appfuse.service.UserManager.getUser=admin,OWNER_STRING_EQUALS
org.appfuse.service.UserManager.getUsers=admin
org.appfuse.service.UserManager.removeUser=admin,OWNER_STRING_EQUALS
org.appfuse.service.UserManager.updateUser=admin,OWNER_USER_EQUALS
</value>
</property>
</bean>
}}}
You will notice that {{saveUser}} is not in the list because it is a public method, and the {{tomcat}} role is no longer needed because the user must be authenticated in order for either of the {{OwnerVoter}}'s to grant access.
!! Test All [#5]
{{ant test-all}} should work now. It is difficult to show any differences in the security now that we have added this to the service layer. That is because the User object is pretty well protected in the UserAction. The main reason I wanted to make this is for other objects in people's apps based on AppFuse that have not had the same level of scruty in the controller as {{User}}.

Back to AppFuseSecurityMethods2, or to the Page History.