[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[ecf-dev] remote service call authorization implemenation

Hi Scott, all,

I would like to add remote service method authorization on ECF remote services. The goal of this email is twofold : first I would like to have some comments on the way I want to use the existing API's and second I would like to have your opinion on some API extension to make the method invocation authorization possible.
Here's a description of what I would like to achieve:
- Client connects to server with some credentials
- Server authenticates the client with the given credentials, retrieves the authorization roles for the given credentials and links those authorization roles to the client container ID
- For each remote service call done from the client, server checks if service method call is authorized for the given client container ID
- Server cleans up relation between authorization roles and client container id when client disconnects (or user logs off)
FYI: The real authentication and authorization wiill be done by spring security, ECF generic will be used to provide the information needed for authentication and authorization.

There's enough API in ECF to provide information for the authentication part:
- Client creates container
- Get ISharedObjectContainerClient interface from the container.
- Set an implementation of IConnectInitiatorPolicy on ISharedObjectContainerClient that will return the needed connect data to pass to the server
- Create an implementation of IConnectContext containing the needed connect data
- call connect method on container with the own IConnectContext implementation

- Server creates container
- Get ISharedObjectContainerGroupManager interface from the container
- Set an implementation of IConnectHandlerPolicy on ISharedObjectContainerGroupManager that will 
      + get the connect data 
      + use this connect data to authenticate (via spring security)
      + if authentication fails throw an exception
      + if authentication succeeds: retrieve the authorization roles (via spring security) for the authenticated user and link this to the client container ID (fromID arg in IConnectHandlerPolicy.checkConnect) --> question: is the client container ID unique?

For the authorization of remote service call there's as far as I know no API available, so I checked what is needed and came up with a proposal API. I tried to make the API generic enough to support several authorization implementations, provider independent and at the same time fitting ECF generic implementation and spring security integration.
So what I need is a way to intercept the remote service call at the server side to do some authorization checking (or in my case to provide the needed information to spring security). It's important to have the interception "around" the remote service call such that authorization specific code can be performed before and after the remote service call (in my case some authorization info would be put before the service call for spring security and cleaned up after the call). In ECF generic implementation, what I think would be the right place (but here I'm maybe looking too much at how to integrate with spring security) is in RegistrySharedObject.executeRequest within the run method of the created IProgressRunnable around "localRegistration.callService(call)". I have three reasons to place the authorization interception there:
1. If an exception must be thrown because the call is not authorized the exception will be handled correctly.
2. We're sure not to have any thread context switching from this point to the local service method call (at least not in the ECF layer, you can still have thread context switching within the service method call but that's application specific).
3. It's the last method having all information needed for authorization: ID of the caller (client container), method call and service on which call is performed.

For the API, I was thinking to have a policy interface (like the IConnectInitiatorPolicy and IConnectHandlerPolicy) that can be set on IRemoteServiceContainerAdapter interface (question: is this the right place? Because IRemoteServicecontainerAdapter looks more a client oriented interface while the IRemoteServiceCallPolicy is more a server thing), for example:

public interface IRemoteServiceCallPolicy {
    public Object callWithAuthorization(IRemoteServiceRegistration registration, IRemoteCall call, ID fromID) throws Exception;

and on IRemoteServiceContainerAdapter there should be a new method:

public void setRemoteServiceCallPolicy(IRemoteServiceCallPolicy policy);

The last thing to do would then be to implement the method setRemoteServiceCallPolicy on RegistrySharedObject class should then and Update the method RegistrySharedObject.executeRequest:
try {
   if (remoteSeviceCallPolicy != null) {
      result = remoteServiceCallPolicy.callWithAuthorization(localregistration, call, responseTarget);
   } else {
      result = localRegistration.callService(call);
   response = ...
} catch...

There's one thing that bothers me with this solution: an implementation of the IRemoteServicecallPolicy.callWithAuthorization would need to have ECf generic internal knowledge to be able to  call localRegistration.callService method because this method is not part of the IRemoteServiceRegistration interface.

Another (maybe better) solution could be to have an interface with a pre invocation hook and a post invocation hook. The preinvocation hook can then be used to authorize the service method call and the post invocation hook can be used to clean up authorization data that was set up at the preinvocation hook.
public interface IRemoteServiceCallPolicy {
    public void preInvocationHook(IRemoteServiceRegistration registration, IRemoteCall call, ID fromID) throws Exception;
    public void postInocationHook(IRemoteServiceRegistration registration, IRemoteCall call, ID fromID) throws Exception;
RegistrySharedObject.executeRequest method should then be changed to:
try {
   if (remoteServiceCallPolicy != null) {
      remoteServiceCallPolicy.preInvocationHook(localregistration, call, responseTarget);
   result = localRegistration.callService(call);
   response = ...
} catch ... {
} finally {
   if (remoteServiceCallPolicy != null) {
      remoteServiceCallPolicy.postInvocationHook(localregistration, call, responseTarget);

What's you opinion on this?