Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Rich Client Platform (RCP) » Enable a handler based on roles required for the method it is calling
Enable a handler based on roles required for the method it is calling [message #516508] Wed, 24 February 2010 09:38 Go to next message
Peter Rademaker is currently offline Peter RademakerFriend
Messages: 4
Registered: February 2010
Junior Member
I would like to disable/enable a handler based on the role required for the service method it is calling and the role of the logged in user. (let's assume for simplicity that a user can have only one role)

I've defined the role required for a service method at its declaration using the Spring Security @Secured annotation as follows:
public interface IExampleService {
    @Secured("ROLE_ADMIN")
    public void exampleSecuredMethod();
}


It would therefore be nice if I would not have to repeat myself when enabling/disabling handlers which call these service methods.
After all, the role required for calling the method should be obtainable by reflection.

Ideally, I would like to be able to do something like this:
<extension
	point="org.eclipse.ui.handlers">
	<handler
		class="com.example.ExampleHandler"
		commandId="com.example.exampleCommand">
		<enabledWhen>
			<with
				variable="com.example.roleLoggedInUser">
				<test
					property="com.example.RoleRequired"
					args="com.example.ExampleHandler" />
			</with>
		</enabledWhen>
	</handler>
</extension>

<extension
	point="org.eclipse.core.expressions.propertyTesters">
	<propertyTester
		class="com.example.RolePropertyTester"
		id="com.example.rolepropertytester"
		namespace="com.example"
		properties="RoleRequired"
		type="java.lang.String">
	</propertyTester>
</extension>


The (intended) result would be that changes to the security configuration/annotation of service methods are automatically reflected in the
enablement of commands in the user interface.


In an attempt to implement this, I've currently created an ISourceProvider which provides the role of the currently logged in user via the variable "com.example.roleLoggedInUser".
However, I'm struggling on how to implement a test to check whether this "com.example.roleLoggedInUser" equals the role that is required for calling the service method.

For now I came up with the idea of havin a PropertyTester which takes the classname of the handler for which the <enabledWhen> clause is defined as argument and returns whether this handler should be enabled based on the role of the logged in user.
For this to work the handler should implement something like an IRoleProvider interface which defines a method getRoles(). My handler implementation
would then use reflection to return the role that is required for calling the service method.

The test(..) method in RolePropertyTester should then look something like this:
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
	if ("RoleRequired".equals(property) && receiver instanceof String) {
		String roleLoggedInUser = (String)receiver;
		String enclosingHandlerName = (String) args[0];
			
		// Do something to obtain the handler for which this property tester was called.
		IHandler enclosingHandler = ...
			
		String roleRequiredForServiceMethod = ((IRoleProvider)enclosingHandler).getRoles();
			
		return roleLoggedInUser.equals(roleRequiredForServiceMethod);
	}
	return false;
}


But I do not see how to obtain a reference to the handler enclosing/defining the command core expressions in which I use the property tester.
As you can see I've tried to pass the handler class as argument, but I do not know how to proceed from there.


Is this the way to go? If so, how can I obtain a reference to the handler in my RolePropertyTester?

If not, what would be a viable way to implement something like this?

[Updated on: Wed, 24 February 2010 10:35]

Report message to a moderator

Re: Enable a handler based on roles required for the method it is calling [message #516590 is a reply to message #516508] Wed, 24 February 2010 13:50 Go to previous messageGo to next message
Paul Webster is currently offline Paul WebsterFriend
Messages: 6859
Registered: July 2009
Location: Ottawa
Senior Member

it seems like you want to annotate your class itself with part of your
expression (the role it supports). If you're going to do that, why not
simply calculate it in your handler's setEnabled(*)/isEnabled(*) methods?

Until the handler is loaded, the commands will look enabled. When it is
loaded, it will be correct because it will have the chance to check its
own security permissions.

The problem you're encountering is that enabledWhen is declarative (to
help avoid class loading) but you need some classloading of your handler
to get the information you've set. Except it becomes complicated when
the object that needs information (your PropertyTester) is instantiated
by one bundle but the handler class could live in another (and the
PropertyTester bundle has no way of seeing that classloader, that's why
we make heavy use of extension points/extetions).


If your set of IExampleServices is not extensible you could use that in
your property tester and depend on the fact that the property tester and
interfaces are all in the same bundle to load the interface class from
the string.

Then your enabledWhen is basically stating that this handler will
implement "IExampleService".

PW

--
Paul Webster
http://wiki.eclipse.org/Platform_Command_Framework
http://wiki.eclipse.org/Command_Core_Expressions
http://wiki.eclipse.org/Menu_Contributions
http://wiki.eclipse.org/Menus_Extension_Mapping
http://help.eclipse.org/galileo/index.jsp?topic=/org.eclipse .platform.doc.isv/guide/workbench.htm


Re: Enable a handler based on roles required for the method it is calling [message #518200 is a reply to message #516590] Wed, 03 March 2010 13:30 Go to previous message
Peter Rademaker is currently offline Peter RademakerFriend
Messages: 4
Registered: February 2010
Junior Member
Paul, thanks for your reply, it helped me a lot.
I have been away for a few days so I've not been able to reply any sooner.

Since it may be useful to others I'll explain shortly what I've done for now. (Which was inspired by the insights I've obtained from your post)
I'm still not completely happy with it (in some way it does not feel completely right) but it works well and fits most of our requirements.
I did have to drop the requirement/idea of having the handler itself providing the method it calls to the propertytester.

Our RCP application depends on a set of libraries (in-house and third party)
which we've added as "one big bundle". For some of these libraries in this bundle to work
we had to use Buddy-Classloading.

In this bundle I've created an IAuthorizationService with a method isAllowedToCall(Collection<GrantedAuthorities>, String className, String methodName)
Its implementation is also in that bundle, thus with help of the buddy classloading it should be able to load the necessary classes.

The IAuthorizationService is called from an AuthenticationPropertyTester, passing in a collection of granted authorities from the Authentication object and the classname and methodname which were provided as arguments.

The core expressions then looks as follows:

<enabledWhen>
    <with variable="com.example.security.currentAuthentication">
        <test property="com.example.security.isAllowedToCall" 
                  args="com.example.IExampleService,exampleMethod" />
    </with>
</enabledWhen>


A disadvantage of this approach is that there is still some duplication in the sense that the service method
which is called by the handler is repeated in the command core expression.


[Updated on: Wed, 03 March 2010 13:32]

Report message to a moderator

Previous Topic:Activate plugin on one editor
Next Topic:Jobs API: Notify when Jobs finished
Goto Forum:
  


Current Time: Tue Mar 19 09:58:43 GMT 2024

Powered by FUDForum. Page generated in 0.02610 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top