Announcement Announcement Module
Collapse
No announcement yet.
Commands/Roles and dynamic menus? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Commands/Roles and dynamic menus?

    Hi All,

    I am facing a classic issue with users and Roles in a multi-tier environment. Upon login, the GUI will receive a list of commands that the user is allowed to perform.

    I would like the menu to be adapted at that time, the unauthorised commands could either be disabled or made invisible on Menu/shortcuts/toolbar.

    How would you do this?
    Is there any recommended way since the menus and toolbars are tailored via XML in Spring RC...well before the login...

    Any suggestion welcomed

    Many thanks,

    Best regards

    Benoit

  • #2
    More thoughts...

    More thoughts on this... and the beginning of an investigation...

    I believe that the main difficulty is based around the programmatic access to the menu.

    1. Accessing the menu, from a View I do
    Code:
    CommandGroup menu = getApplication().getLifecycleAdvisor().getMenuBarCommandGroup();
    I assume that it is working fine.

    The CommandGroup lets you find Commands but does not let you iterate through them. Although, it was probably defined for encapsulation, this is unfortunate in my opinion. When a user is logged in, the client context would receive a list of authorised commands, security nearly always works by giving rights and not eliminating existing ones.

    Basically you would receive a list of command for which one should call setEnabled(true) on and setEnabled(false) on the other ones...

    By not being able to iterate, we then require the knowledge of all possible commands in order to enable/disable them.

    Furthermore, using the CommandGroup.find(...) requires the knowledge of the full path to the command. One could assume that this is not required for security... It is probably preferrable not to rely on a full path but simply say that "showPetOwnerView" should be disabled, being in "fileMenu/showPetOwnerView or window/showView/showPetOwnerView...

    What stops us from doing this?
    The method CommandGroup.getMemberList is unfortunately protected.
    I would therefore suggest that we open it up, may be by providing an iterator or returning an unmodifiableList.

    What do you think? Am I moving in the right direction or is there a better way?

    I may raise a JIRA for it.

    Alternatively, we could build the dynamic aspect in CommandGroup by creating 2 methods:

    Code:
    public void setEnableEndCommands(boolean enable, Set endCommands)
    public void setVisibleEndCommands(boolean visible, Set endCommands)
    These 2 methods would iterate through the member list and if a command id is found in the endCommands it would enable/disable or make it visible/invisible.

    Would this be better? It would also work for Toolbars!

    I do not think that it is easy to extend CommandGroup as it is used in different factories, I would suggest to either:
    - make the getMemberList public
    - or add those 2 methods in CommandGroup

    What do you think? I will give it a go and report back but please let me know if I err as I am only human! ;-)

    2. second question: Where to put this "security" code, in my view, it should run just after the login (at that point my app knows the authorised commands)... How would you trigger the code? Is there an login event? How can I subscribe to it?

    Many thanks

    Benoit.

    Comment


    • #3
      a solution

      Here is a solution with patch and unit test.

      I hope that the change will be approved to go in PR1.

      http://opensource2.atlassian.com/pro...browse/RCP-208

      comments/suggestions?

      Thanks

      Benoit

      Comment


      • #4
        Re: Commands/Roles and dynamic menus?

        I faced a similar problem recently, although not security based, but basically one where I had a number of commands that I needed to enable/disable based on the state of the application. I ended up solving it a different way which may or may not be applicable in your case.

        In my case the command being enabled/disabled depended on a set of rules based on what I'll call symantic state. That symantic state could change by selecting different objects in different views, and in theory across views. The application was getting complex (ie a pain) to expand by adding new commands, a sure sign I needed to change something.

        So, i ended up firing an internal application event on object selection and made the commands listeners to that event. The command themselves could then determine whether to enable or disable themselves. In your case you could, for example, fire a security event after login (and relogin if needed) and have the command listen for security events configuring themselves based on the payload of the event. Also, if in the future you end up having other situations that change the security settings all they would need do is fire an event corresponding to that change.

        Currently, i like this solution. It seperates ui state from symantic state by a clear, expandable set of rules and it allows commands to configure themselves by listening for events that signal potential changes in state.
        Adding new commands is straight forward as the views do not need to concern themselves with command enabling/disabling.

        Originally posted by benoitx
        Hi All,

        I am facing a classic issue with users and Roles in a multi-tier environment. Upon login, the GUI will receive a list of commands that the user is allowed to perform.

        I would like the menu to be adapted at that time, the unauthorised commands could either be disabled or made invisible on Menu/shortcuts/toolbar.

        How would you do this?
        Is there any recommended way since the menus and toolbars are tailored via XML in Spring RC...well before the login...

        Any suggestion welcomed

        Many thanks,

        Best regards

        Benoit

        Comment


        • #5
          I require this functionality too.

          In a webcontext acegi has tags for this.
          Something like <acegi:ifUserHasRole role="myrole"/>
          The nicest way to configure this would be in the commands xml.
          To be able to put a role on each command which makes it invisible.

          Comment


          • #6
            Hi

            Thanks for your comments. 2 thoughts:

            1/ Configuring via XML may be a nice setup but sometimes, one needs the ability to change it at runtime. A command could allowed for multiple roles (as usual ACL are like a growing overlapping set).

            2/ The option of firing events is elegant (could you post some explicit code examples) but often, the need is to enable some and disable other. Firing an series of separate events (say one for each authorised command or role) would not given the sense of authorised "set".

            eg, firing "save", "exit" events would not tell the "close" command that it needs to be disabled or invisible? How would we distinguish between the 2 handling?

            The event fired should contain all authorised commands in one go and we must ensure that all commands listen to it, if their id is not part of the event, they should disable or make themselves invisible (or to decide?).

            Both very good ideas but PR1 is around the corner... so we need a solution now... or may be something a reasonable temporary solution that can be amended later?

            Feel free to comment on the RCP

            Best regards

            Benoit.

            Comment


            • #7
              My last post probably wasn't the clearest of all... usual when pressed by time to go to a meeting.

              I can see one issue with configuring the roles in xml. Any application would have to have such a setting, being the 'standard' commands like open/save/login or logout.

              The xml would become big but I can live with that.

              The issue with the command itself knowing when to enable/disable itself based on a role is similar (ie it needs to be setup explicitely). If it based on the command I'd then we could design the command to respond to an event.

              So I think it would be good to separate the role and the mapping to command ids. This way, that mapping could come from db, xml or an ldap server. Once gui has that list of authorised commands, we can look at how to act on it.

              I think it is important to either have a way to find all commands and iterate through them with the authorised list or have, by default, any command listening to 'authorisation' events. At the moment, I believe it is not possible to iterate through the command, but then I may be wrong...

              As mentioned before, the authorisation event should have the full list of authorised command ids. Let me explain:

              Assume that we have 3 commands a,b,c. Assume also that only a and b are authorised.

              If we fire individual events a and then b; how would c know that it should be disabled? The entire list should be part of the event and all commands should listen to it, if the commandId is not part of the list then it should be disabled or invisible.

              This event mechanism would work nicely until we consider the ergonomics of an application. For instance if all commands of an entire menu or submenu were disabled, shouldn't the menu be also disabled?

              I would recommend designing the authorised commandIds to take into account a path as I think it is irrelevant how they are accessed vs the need to disable them.

              So the idea of traversing menus as per rcp 206 probably offers the best ergonomics.

              However it would require to know the top CommandGroup that should be traversed (like menuBar and toolBar) and may be there is a command accessible somehow differently.

              How could we merge the idea of events and menu ergonomics? And best of all, how could we make it with the least amount of changes so it may have a chance to get into PR1?

              Comments?
              (Btw I won't be around until oct 6)

              Best regards
              Benoit

              Comment


              • #8
                So I think it would be good to separate the role and the mapping to command ids. This way, that mapping could come from db, xml or an ldap server. Once gui has that list of authorised commands, we can look at how to act on it.
                Do we really need the roles softcoded?
                I cannot image a db or ldap that specifically says which command to show or not for which role, this is db migration hell when a command is added or renamed.

                I 'd propose (actually I stole the idea from acegi's web tags):

                Any application defines a set of roles (admin, employee, customer, ...).
                The nice thing about these roles is that they group a set of authorizations.
                Users are dynamically allowed to use a command based on the roles (comma-seperated) allowed for that command.
                1 command has 1-n roles (default is all).
                1 user has 0-n roles (or 1-n with default is anonymous).
                An outside db or ldap could map it's own roles to our applications roles (like happens now in deployment descriptors).

                Web applications using acegi currently do it like this, so I think this is a good practice.

                Comment


                • #9
                  most banking app I worked on prefered a centralised mapping Roles/commands... so you can modify it without having to change anything on the client.

                  Putting it in XML which in turn is placed in the application jar (like petclinic) would imply a new release for a mapping change... I know that this is not that painful with webstart, but it would look bad that clients have to re-download the app to fix it...

                  Hence my suggestion to separate them... may be build a system that could do both? either having the mapping in xml or receiving a list of mapped commands from somewhere? At the end we need this list of authorised commands before applying it...

                  Cheers

                  Benoit

                  Comment


                  • #10
                    Benoit,

                    As for the event firing, I would agree with you, the level of event should be higher than individual commands. As you say, containing the list of all authorized commands would probably be the most straightforward. I guess it all depends on how the allowed commands are stored in the db.

                    The more I think about the situation you are describing I don't think the event solution is ideal. I certainly don't use it for all my commands, only those whose enabling logic is not localized (easily) to one view, and so a distributed event concept fits.

                    I'd agree, the most straightforward (and generic) way to solve this would be to iterate through the complete list of commands. The problem then becomes what is being discussed - how to map roles to commands.

                    I'm lucky, I don't have any security issues with my current app.

                    FYI: For my internal application events I'm using the event listening framework at https://elf.dev.java.net/ and I'm finding it very useful. It allows you to specify your own events and listeners and provides event channels to dispatch events of the correct type to their appropriate listener. The events can have multiple types which can then be mapped to different methods in the listener (much the same way as awt events) which allows symatic grouping of internal events.

                    Jonny

                    Originally posted by benoitx
                    Hi

                    Thanks for your comments. 2 thoughts:

                    1/ Configuring via XML may be a nice setup but sometimes, one needs the ability to change it at runtime. A command could allowed for multiple roles (as usual ACL are like a growing overlapping set).

                    2/ The option of firing events is elegant (could you post some explicit code examples) but often, the need is to enable some and disable other. Firing an series of separate events (say one for each authorised command or role) would not given the sense of authorised "set".

                    eg, firing "save", "exit" events would not tell the "close" command that it needs to be disabled or invisible? How would we distinguish between the 2 handling?

                    The event fired should contain all authorised commands in one go and we must ensure that all commands listen to it, if their id is not part of the event, they should disable or make themselves invisible (or to decide?).

                    Both very good ideas but PR1 is around the corner... so we need a solution now... or may be something a reasonable temporary solution that can be amended later?

                    Feel free to comment on the RCP

                    Best regards

                    Benoit.

                    Comment


                    • #11
                      I would agree that the event model is a non-starter (for all the reasons epxressed and a few more).

                      I think, however, that this problem is a little more general than just role-based control over commands. It is really more a question of how to configure commands (visible or not, enabled or not) based on lifecycle events in the application.

                      Right now, I can retarget shared commands by using a TargetableActionCommand. However, in cases where the executor is set to null, the command is simply disabled - whereas I would like it to be made non-visible.

                      So, I would think that we need to combine these desired control requirements and create a lifecycle for the commands. This would allow for things like view changes, window open/close, focus changes, security changes (login/logout), etc. With a more general model, we can accommodate a broader set of requirements for managing commands.

                      How does this sound?

                      Larry.

                      Comment


                      • #12
                        Hi Larry

                        That sounds great. I was starting to think about commands that are inside forms... Their Ids may be the SAME accross several forms and, from a security perspective this may not be ok...

                        Example:
                        say your role is Trader, you can see the Bank static data but cannot change it.
                        Another role is StaticDataManager and not only can you see the static data but you can change it as well...

                        Ideally one would you the same view and same forms for both viewing/editing. In one case the form should have a disabled "OK" button (the okCommand) but this okCommand is used in other screens... where Trader may need to have it enabled.

                        So may be I'll have to create different commands for each dialog/view by overriding the getCommandGroup (or similar)... or may be we can think of something better...

                        It also had crossed my mind that sometimes one may want the same command but different titles...but that is another story.

                        Any suggestion/Idea?

                        Benoit

                        PS: I shall be offline til Oct 5 (enough stupid questions for a while... :-)

                        Comment


                        • #13
                          Example:
                          say your role is Trader, you can see the Bank static data but cannot change it.
                          Another role is StaticDataManager and not only can you see the static data but you can change it as well...

                          Ideally one would you the same view and same forms for both viewing/editing. In one case the form should have a disabled "OK" button (the okCommand) but this okCommand is used in other screens... where Trader may need to have it enabled.
                          Acegi's view tags do it like this, it's kinda like "if any of the following roles are met, enabled/show (configuratable) this button"


                          If you put the role to commands in the database, each time you add a new command (a new button for example), you might have migrate/update your database upon deployment.
                          The alternative is to just declare your roles fine-grained enough.

                          I see a role as a group of commands that are allowed.
                          Acegi's web tags also hardcodes 1 command to a set of role.

                          If you allow the admin to specify each command seperatly, he could disable create & delete, but for example forget edit. While if you just have a role "write" (create, edit & delete) to enable, it's nicely grouped. This could even be a course-grained role, making new functionality added upon a new deployment authorized correctly for users with(out) the course-grained role.

                          In any case, it would be nice to allow a simple xml resource (maybe part of the commands xml) to declare which roles can use which buttons.


                          Examples of command grouping authorization into a role:
                          read: view
                          write : view, create, edit, delete
                          clipboard : cut, copy, paste
                          support : emailSupport, sendBug, ...

                          User x has roles read, write, clipboard
                          Yours roles is like your keyset, just try every key on your keyset to open one of the car doors untill you get in (or not). Having a wrong key doesn't stop you from trying another key.

                          Comment


                          • #14
                            I'd say that we should split the way the authorised commands are gathered and the way we propagate it in the app. May be 2 implementations...

                            The reason I am keen on the actual commands to be in the DB is that I have worked on applications that have a WEB and GUI clients and for which the authorised commands must be the same. Hence the idea of storing them in the DB.

                            Shall we open a Wiki page for this or carry on in the forum? I would like to make some progress and see feedback from the core team on some ideas.

                            http://opensource2.atlassian.com/pro...browse/RCP-208 may be simplistic but I believe that it kind of solve the menu/toolbar functionality. It certainly detects the "empty menu and sub-menus".

                            How could we tackle the issue of "actions" that are on forms/dialogs etc... A straightforward event mechanism may work for them... I was thinking that may be ActionCommands could subscribe to ApplicationEvents? They could reply only to "ACLEvent" type. I am unsure about this option though, we know that there would NOT be many ACLEvents (only at login time!) but I do not know about the amount of other events that could be listened to by the commands...

                            Any way, Wiki or this thread?

                            Oliver/Larry & core team, how do you this working?

                            best regards

                            Benoit

                            Comment


                            • #15
                              thinking a bit further...

                              Not all commands exist once the user has logged on... some maybe created only when a view or form in a dialog is launched...

                              So,
                              menu & toolbar could be treated at login time
                              but other commands should be treated when they are created... they would require access to a "service" or something like this... that would simply say: enabled/disabled/invisible.

                              Any suggestion?

                              Benoit

                              Comment

                              Working...
                              X