Details
-
Type:
Bug
-
Status:
Resolved
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 2.3
-
Fix Version/s: 2.4.1
-
Component/s: Displayers
-
Labels:None
Description
Copied from SF http://sourceforge.net/tracker/index.php?func=detail&aid=1060402&group_id=48726&atid=453974:
Using VelocityMenuDisplayer to display menus with role
restrictions, after loggin in as a user with more
restrictions (less menu items visible), then logging in
as a user with less restrictions (more menu items
visible) : result --> the menu item that is role
protected does not show anymore for the less restricted
user. Cause: caching the menu probalby and the code in
VelocityMenuDisplayer around line 175 that removes the
item from the menu. Possible solution:
The code below to be run against a clone instead of the
menu object and that clone put in the context afterwards.
menu.getComponents().clear();
menu.getComponents().addAll(componentsAllowed);
Comments
Date: 2005-05-20 15:48
Sender: wrschneider99
Logged In: YES
user_id=768885
One of the developers I work with arrived at a simple solution:
eliminate this logic entirely from the Velocity displayer
and make the template do the work. the template can just do
#if ($displayer.isAllowed($menu))
This maintains the spirit of the Velocity displayer as
mainly a pass-through to shove stuff into a VelocityContext.
In most cases our menu.vm template is already recursive,
and the VelocityMenuDisplayer was actually not handling
permissions properly for the sub-items (items below another
item rather than the top-level menu).
Date: 2005-05-18 15:49
Sender: razvan11
Logged In: YES
user_id=919177
Your comment is correct. In the application for which I
described my solution, one has to log in before he sees any
menus rendered by StrutsMenu. With the code at hand, this
solution was the least code intrusive. The filter builds
and stores the menu after the login.
Dynamically producing a role based filtered menu for each
rendering would for sure by more appropiate.
Date: 2005-05-18 14:16
Sender: wrschneider99
Logged In: YES
user_id=768885
Another use case to consider: your roles may change in the
scope of a single HttpSession because you might display the
menu before typing the username and password.
I believe this is a legitimate bug, because it violates the
"principle of least astonishment": a new user would
not
expect this kind of interaction between the provided Struts
plug-in (or analogous Bean to use with Spring), the
rolesAdapter and the VelocityMenuDispl.
Also, one would think that it's odd semantics for a
MenuDisplayer to mutate the passed-in MenuComponent.
Date: 2005-05-18 14:06
Sender: razvan11
Logged In: YES
user_id=919177
On second thought, this is not a bug. The limitation occurs
from the fact that the menu is loaded at server startup and
shared among all users/sessions within the server. The
solution is to change the way the loading of the menu
resource is done so that each new session gets it's own
copy
and can properly filter out items based on the specific user
role. As such, I have eliminated the menu preloading via the
struts-config plugin and created a Filter implementation
which checks/loads the menu resource if it does not exist.
Also, in the JSP pages using the menu tag, I set the
"repository" property to match the name of the
attribute the
filter is saving the menu resource under.
Date: 2005-05-18 13:44
Sender: wrschneider99
Logged In: YES
user_id=768885
Found the same bug. Any chance of a 2.3.1 patch release?
Date: 2004-11-18 03:33
Sender: uded
Logged In: YES
user_id=126964
One must change some lines to do so, but it's quite
simple.
>>>> File: VelocityMenuDisplayer.java
Change lines 165-176:
— From:
// update menucomponents with only allowed
components
List componentsAllowed = new ArrayList();
MenuComponent[] components =
menu.getMenuComponents();
for (int i = 0; i < components.length; i++) {
if (isAllowed(components[i]))
}
menu.getComponents().clear();
menu.getComponents().addAll(componentsAllowed);
+++ To:
// update menucomponents with only allowed components
List componentsAllowed = new ArrayList();
MenuComponent[] components = menu.getMenuComponents();
for (int i = 0; i < components.length; i++) {
// Case 1 - there is no submenu
if (components[i].getMenuComponents().length
== 0) {
if (isAllowed(components[i]))
// Case 2 - some submenus
} else {
MenuComponent mc = components[i];
// I assumed that the user must have
permission to parent level
// of the menu to consider the submenu
at all
if (isAllowed(mc)) {
MenuComponent[] subComponents =
mc.getMenuComponents();
for (int k = 0; k <
subComponents.length; k++) {
if (isAllowed(subComponents[k])
== false)
}
// In case if there are some
submenus with proper permissions
// for that user we're checkin if
there won't be some nulls
// in main params and then adding
everything to componentsAllowed.
if (mc.getMenuComponents().length >
0 || mc.getAction() != null || mc.getAction().length() > 0
mc.getForward() != null ||
mc.getForward().length() > 0 || mc.getLocation() != null ||
mc.getLocation().length() > 0 ||
mc.getPage() != null || mc.getPage().length() > 0)
}
}
}
MenuComponent localMenu = new MenuComponent();
localMenu.getComponents().addAll(componentsAllowed);
In file MenuComponent add a method at line ~57:
public void removeMenuComponent(MenuComponent
menuComponent) {
if (menuComponents.contains(menuComponent))
}
This should do it.
Related: http://sourceforge.net/tracker/index.php?func=detail&aid=1358227&group_id=48726&atid=453976