Passing security context to authorizer

Posts   
 
    
ww
User
Posts: 83
Joined: 01-Oct-2004
# Posted on: 05-May-2009 22:35:19   

I am looking at using the Authorization framework. Security in my application is based on a security principal, but not the principal associated with the application or thread. So I need somehow to pass the correct security principal to the authorizer.

The easiest way I found was to subclass the Context class with MyContext, which also stores the user identity used to perform validation. I then make sure to always use this context for entities, so the authorizer can get the ActiveContext, cast it to MyContext, and get the security principal from that.

This works fine except in CanLoadEntity, because the object hasn't been loaded yet, so there's no ActiveContext.

The other approach I considered is using a dependency injection scope to inject an authorizer instance that knows the identity to validate against. The problem here is that once it's loaded, the scope applies to all objects created in the thread, which isn't what I want--a thread may be working with more than one security "context".

Essentially what I have is a "DataManager" class that encompasses a Context and a DataAdapter, and which has a security identity associated with it. I need all objects retrieved by that adapter to validate security against the identity associated with the DataManager that owns it.

Has anyone implemented something similar?

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 06-May-2009 09:09:47   

It should be the responsibility of the Authorizer to find out who is the current caller (user requesting some action). Would yo please check the Authorization example posted on the downloads section of llblgen.com

ww
User
Posts: 83
Joined: 01-Oct-2004
# Posted on: 06-May-2009 15:30:29   

Walaa wrote:

It should be the responsibility of the Authorizer to find out who is the current caller

The problem is that authorization is not based on the "caller". It's based on an arbitrary user token, and there's no reliable way to get that token to the authorizer, because entities aren't part of any sort of session or context aside from (sometimes) the uniquing context.

The discussion in the llblgen help uses the thread owner identity for authorization, which doesn't work for me because the thread won't be running under the user's identity. The example project is further away from what I need, because it's relying on a globally-stored user identity.

I am working on a server application that handles client connections through remoting. The server will be not be running under the client's identity, but it will have a token for the client.

When servicing a client request, I need to be able to authorize against that client's token, but without impersonating the client (so the thread owner approach won't work).

As I mentioned in my first post, I could use a dependency injection scope to create a separate authorizer instance for each client request, and store the identity in the authorizer. The problem here is that if my thread also needs to do some work that isn't subject to authorization checks, I have to destroy that injection scope to switch back to the correct security context, and then re-create it to go back to authorizing.

My thread may have two separate DataAdapters: one for working with objects subject to authorization, and one for working with objects that are not subject to authentication. What I need is a way to have a different authorizer for each of those adapters.

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 06-May-2009 15:41:37   

The server will be not be running under the client's identity, but it will have a token for the client.

When servicing a client request, I need to be able to authorize against that client's token, but without impersonating the client (so the thread owner approach won't work).

Can't the Authorizer requestthe token from the Server? Did you check the published full authorization example (downloadable)?

ww
User
Posts: 83
Joined: 01-Oct-2004
# Posted on: 06-May-2009 15:52:02   

The full authorization example uses a static LoginHelper class that stores a static user identity after logon. All the authorizers then use this identity. This only works for an application that's servicing one user at a time.

My application may be handling requests from 10 different users at a time. The Authorizer can't ask the server for the user token because the server wouldn't know which of the 10 different user tokens to give it.

I just looked again at dependency injection scopes and realized that won't work like I thought it would, because DI won't let me provide an instance of an authorizer to inject--it only accepts a type and creates the instance itself.

My original idea--using the Context--seems to be the closest I can get using the llblgen framework, though it fails in loads where the context has not been set. I guess I'll have to use that approach and supplement it with my own filtering of objects after the fetch is complete.

Walaa avatar
Walaa
Support Team
Posts: 14946
Joined: 21-Aug-2005
# Posted on: 06-May-2009 16:55:26   

I don't like it but it's the only solution I can think of at the moment, is that the UserID is sent to the BL method which in turn gets responsible of creating the Authorizer and passing in the UserId, and attaching this Authorizer instance to the entity (entities being fetched).

ww
User
Posts: 83
Joined: 01-Oct-2004
# Posted on: 06-May-2009 18:21:01   

This is essentially what I'm doing, but using the Context to carry this information. It works for single-entity fetches, because I can assign the Context before I do the fetch. But in collection fetches, the Context doesn't get set for entities before the authorizer is called. I guess I need to look at modifying the EntityCollection to do this.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39590
Joined: 17-Aug-2003
# Posted on: 07-May-2009 10:15:50   

I see your problem, the thing is though that in your case, what's allowed and what not depends on the code consuming the entity, not the entity and its authorizer. So in effect, the authorization is external to the entity, simply because if an entity is moved from method A to method B, it might be that other security rules exist: at some point when a piece of code wants to do something with an entity, what exactly decides what's allowed and what not? If it's the token, the token either has to be inserted inside the authorizer, or the authorization logic has to be external where the token is located as well. Otherwise it makes little sense.

All entities you don't create through 'new' yourself are created through a factory. These are generated classes and it might be the 'best' starting point for injecting the token into an entity or its authorizer. The order in which things happen is: factory calls Create, Create calls constructor, constructor calls DI elements, so after the ctor, all DI logic has ran. So for example you could try to use a custom factory class which inserts the token into the authorizer. Factories are also obtained from entity types through their method 'Create'. The 'best' way to extend these factories is by a custom template or by adding custom code to the code region in the factory.

The main problem still exists, the authorizer inside the entity has to contact an element outside the entity if something is allowed. That element has to give the solid 'reality' to the authorizer to allow or deny some action. I.o.w.: if you have to call to the outside world, why not do that directly there? You can override Can... methods in an entity (e.g. through a partial class) and call authorization logic as well. However this gives a catch 22: you've to pass the token to the authorization logic and you don't have the token there.

May I ask why you don't spawn a thread per client? It would make things much easier as you could use thread principal and also [ThreadStatic] to create thread local storage.

Frans Bouma | Lead developer LLBLGen Pro
ww
User
Posts: 83
Joined: 01-Oct-2004
# Posted on: 07-May-2009 15:42:42   

Otis wrote:

I see your problem, the thing is though that in your case, what's allowed and what not depends on the code consuming the entity, not the entity and its authorizer. So in effect, the authorization is external to the entity

I think authentication always depends on the code consuming the entity--or rather, the user on behalf of whom the code is consuming the entity--rather than on the entity itself.

Otis wrote:

if an entity is moved from method A to method B, it might be that other security rules exist: at some point when a piece of code wants to do something with an entity, what exactly decides what's allowed and what not?

This is not the case with my model. My conception (which I guess is a different pattern than the approach llblgen uses) is that an object is assigned to a "context" or "session" when it is created, and remains there until it is destroyed, and that context determines its security rules.

Otis wrote:

May I ask why you don't spawn a thread per client? It would make things much easier as you could use thread principal and also [ThreadStatic] to create thread local storage.

I do have one thread per client, and I've started looking at TLS. The catch is that while the thread will be servicing only one client, it may also need to do things that the client can't do. For example, maybe the client updates an object, which it has permission to do, but then the service needs to write an audit record, but clients don't have permission to create audit records directly. There are ways other than authorization to handle this, though, so I'm still thinking it through.

Ultimately I may just handle everything outside the llblgen framework, since I have the service layer processing the data requests from the client anyway.

I may also take a look at factory code as you suggested. Thanks for the ideas.