At line 7 added 1 line. |
%%note: __NOTE:__ This guide is currently only for the Struts version of AppFuse. Other frameworks will be added at a later date.%% |
At line 9 changed 2 lines. |
* [1] Updating your ''roles'' |
* [2] Catch the AccessDeniedException |
* [1] (Optional) Add acegi .jar to your Eclipse classpath |
* [2] Add public Methods |
* [3] Prepare your Actions |
At line 18 changed 1 line. |
!!Updating your ''roles'' [#1] |
!!Add acegi .jar to your Eclipse classpath [#1] |
The .jar file for acegi already exists in your project but it probably is not in your Eclipse classpath. You can find it in: |
{{{myproject/lib/spring-1.1.3/acegi-security-0.7-SNAPSHOT.jar}}} |
Other versions should work too, but this is what I had to start with after Matt integrated Acegi authentication. |
At line 25 added 3 lines. |
!!Add public Methods [#2] |
In the case of the UserManager, we will want to add security on {{saveUser()}} |
%%note:__:TODO:__ Fix this... role based security on {{saveUser}} does nothing. remove the unnecessary complexity.%% |
At line 21 changed 1 line. |
!!Catch the AccessDeniedException [#2] |
!!Prepare your Actions [#3] |
There are two issues that will need to be dealt with in your actions. The first is we need to be able to catch a {{AccessDeniedException}} and redirect the user to a 403 error page. This is easy enough to accomplish just by adding the appropriate {{import}} and adding a {{try/catch}} block to the BaseAction.execute() method so it looks like this: |
{{{ |
import net.sf.acegisecurity.AccessDeniedException; |
At line 34 added 1 line. |
... |
At line 36 added 90 lines. |
/** |
* Override the execute method in LookupDispatchAction to parse |
* URLs and forward to methods without parameters. Also will |
* forward to unspecified method when no parameter is present. |
* <p/> |
* Will forward to a 403 server error in the case the user does |
* not have authorization to access a manager method being invoked. |
* <p/> |
* This is based on the following system: |
* <p/> |
* <ul> |
* <li>edit*.html -> edit method</li> |
* <li>save*.html -> save method</li> |
* <li>view*.html -> search method</li> |
* </ul> |
* |
* @param mapping The ActionMapping used to select this instance |
* @param request The HTTP request we are processing |
* @param response The HTTP response we are creating |
* @param form The optional ActionForm bean for this request (if any) |
* @return Describes where and how control should be forwarded. |
* @throws Exception if an error occurs |
*/ |
public ActionForward execute(ActionMapping mapping, ActionForm form, |
HttpServletRequest request, |
HttpServletResponse response) |
throws Exception { |
|
// Capture an AccessDeniedException thrown by Acegi Security |
// and redirect to the 403 server error page |
try { |
|
if (isCancelled(request)) { |
ActionForward af = cancelled(mapping, form, request, response); |
|
if (af != null) { |
return af; |
} |
} |
|
MessageResources resources = getResources(request); |
|
// Identify the localized message for the cancel button |
String edit = resources.getMessage(Locale.ENGLISH, "button.edit").toLowerCase(); |
String save = resources.getMessage(Locale.ENGLISH, "button.save").toLowerCase(); |
String search = resources.getMessage(Locale.ENGLISH, "button.search").toLowerCase(); |
String view = resources.getMessage(Locale.ENGLISH, "button.view").toLowerCase(); |
String[] rules = {edit, save, search, view}; |
|
// Identify the request parameter containing the method name |
String parameter = mapping.getParameter(); |
|
// don't set keyName unless it's defined on the action-mapping |
// no keyName -> unspecified will be called |
String keyName = null; |
|
if (parameter != null) { |
keyName = request.getParameter(parameter); |
} |
|
if ((keyName == null) || (keyName.length() == 0)) { |
for (int i = 0; i < rules.length; i++) { |
// apply the rules for automatically appending the method name |
if (request.getServletPath().indexOf(rules[i]) > -1) { |
return dispatchMethod(mapping, form, request, response, rules[i]); |
} |
} |
|
return this.unspecified(mapping, form, request, response); |
} |
|
// Identify the string to lookup |
String methodName = |
getMethodName(mapping, form, request, response, parameter); |
|
return dispatchMethod(mapping, form, request, response, methodName); |
} catch (AccessDeniedException ade) { |
response.sendError(HttpServletResponse.SC_FORBIDDEN); |
return null; |
} |
} |
}}} |
|
The second consideration for Actions is that public actions (any action that does not require the user to be logged on) can only access public methods on our manager beans. When AppFuse comes out of the box the only action that needs to be modified is {{SignupAction}}. We will need to remove the code that ''automagically'' used to log in a user after signup. It would be possible to still do this, but it is fairly complicated and it's not really that important to me to make the user not have to log in right after creating his account. But the problem with leaving that code in is that is would cause one of the decorator pages to try and access UserManager.getUser() which is protected and an AccessDeniedException will be thrown since our user is not yet logged in. So remove this section of code from {{SignupAction}}: |
{{{ // Set cookies for auto-magical login ;-) |
String loginCookie = mgr.createLoginCookie(user.getUsername()); |
RequestUtil.setCookie(response, Constants.LOGIN_COOKIE, |
loginCookie, request.getContextPath());}}} |
|
|