Creating JMS Dataportal Channels/Routers. A security question.

Creating JMS Dataportal Channels/Routers. A security question.

Old forum URL: forums.lhotka.net/forums/t/977.aspx


slabanum posted on Tuesday, August 22, 2006

Hello,

I am in the process of creating the channels and routers for my JMS implementation of CSLA.NET.  I was able to do this on CSLA.NET 1.1x version but now I am trying to fit it on the channel and router pattern. 

The problem I have is that  I am using windows-based authentication on the client.  The server components are running on a Java Virtual Machine (JMS) which has it's own security/authentication mechanism, but I can have a routine on the server business components to log-in as a valid Domain Account so that windows authentication/role checking can be accomplished.

Looked at the DataPortal.Client.DataPortal module and noticed that the GetPrincipal is returning "nothing" if it is Windows authentication. How can I elegantly work around this?  I need the ApplicationContext.User to be passed in during the creation of the Server.DataPortalContext so that on the server-side I know who the user is.

By the way, I was able to accomplish this on the CSLA.NET 1.1X by serializing the Principal object as a base 64 encoded string and passing it as part of the criteria object, then deserializing it back in the server component..  Kind of a hack since I bypassed the DataPortalContext. 

This time I want to be legit and want to try to use the DataPortalContext. 

Thank you.

RockfordLhotka replied on Tuesday, August 22, 2006

You can use the same basic technique you used in 1.x, but put your serialized Principal as an entry into ApplicationContext.ClientContext. ClientContext is passed from client to server as part of the DataPortalContext, and is designed specifically for this sort of requirement.

slabanum replied on Tuesday, August 22, 2006

Rocky,

Sweet!  Thank you sir.  Never thought of this approach.  Aaah, the version in 1.x  I used never had the ApplicationContext then..it predates the 1.52...never had the chance to update it with the newer releases.

Again, thank you!

slabanum replied on Tuesday, August 22, 2006

Rocky,

Sorry, but I have to ask this questions so it becomes clear. 

1) Where is the most likely place for me to call ApplicationContext.ClientContext.Add("ClientPrincipal", Serialize(GetPrincipal()))?  Should it be on the initialization phase (eg. Form Load or main()) of a UI or should it be during the Initialize() phase of my business object (override Core.BusinessBase.Initialize())?

2) When I check for authorization should I check for it on the ClientContext like the example on DataPortal_xyz:

      if not (Ctype( Deserialize(ApplicationContext.ClientContext.Item("ClientPrincipal"), IPrincipal).IsInRole("SomeRole") then

     throw some exception

    end if

The reason I asked is on the server-side, ApplicationContext.User would return the user that is used to start my server-side component, not the client's principal since Server.DataPortal.SetContext does not set the ApplicationContext.User to the client's principal (In the first place Client.DataPortal's GetPrincipal return's nothing on "Windows" authentication).

During my first stab in the 1.x version I used to set the Principal to the client's principal.

 

I guess this is a trade-off for marrying different worlds of technology.

Thanks.

RockfordLhotka replied on Tuesday, August 22, 2006

So I understand, what you are doing with JMS is passing messages from a .NET client to a .NET server - but that server is hosted within a process created by JMS? And, of course, JMS doesn't have any mechanism by which it can flow the client Windows credentials through to the server for impersonation, so on the server you actually want to use some type of custom principal that emulates the user's Windows identity?

slabanum replied on Tuesday, August 22, 2006

You are right, JMS does not have a mechanism to let the client Windows credentials through to the server for impersonation. 

The .NET server run by a JMS process is running as a windows account though, since the JVM is run as a windows service.

Everytime a message comes in (one of the DataPortal_xxx method), a thread is created and I need this thread to be set to the client Windows principal so that I can use authorization checking by using the Thread.CurrentPrincipal.

I got it to work with 1.x but there has been a big change with 2.x.  I might have to go with a RequestParam object (similar to the DTO in the web service portal) that contains the client's principal and the criteria object and the dpContext.  I worry about using the ApplicationContext.ClientContext because of thread safety if I create an ASP.NET client UI, although I might be wrong.

Thanks.

 

 

 

RockfordLhotka replied on Wednesday, August 23, 2006

slabanum:

Everytime a message comes in (one of the DataPortal_xxx method), a thread is created and I need this thread to be set to the client Windows principal so that I can use authorization checking by using the Thread.CurrentPrincipal.

I got it to work with 1.x but there has been a big change with 2.x.  I might have to go with a RequestParam object (similar to the DTO in the web service portal) that contains the client's principal and the criteria object and the dpContext.  I worry about using the ApplicationContext.ClientContext because of thread safety if I create an ASP.NET client UI, although I might be wrong.



The whole purpose behind ApplicationContext is to support both ASP.NET and non-ASP.NET environments safely. Read Chapter 4 for details on this.

Since you are creating your own data portal channel, you have quite a lot of control over what happens with the principal on the thread. Remember that CSLA .NET does nothing with the principal object if you say you are using "Windows" authentication. ApplicationContext.User merely returns the thread's currentprincipal, and that principal is unchanged by CSLA, because it assumes Windows has set the value.

In your case, YOU can have set the value in your data portal host - and CSLA will just use that value - assuming it was set by Windows.

Given these further details though, I wouldn't use ClientContext to pass the value. The reason is that you need the value in your data portal host, and ClientContext isn't deserialized/available until after the server-side data portal executes (which is after your host's code has run). So what I'd do instead, is pass the principal as a separate parameter - possibly part of a JmsChannelContext parameter.

Remember, your channel has total control over what is passed over the network. Look at the difference between the remoting channel and the web services channel in Chapter 4 - they don't pass the same things, nor in the same manner.

In other words, you can pass the normal data portal parameters PLUS a JmsChannelContext parameter across the wire. Within this JmsChannelContext parameter you can include the principal object, which your host can put onto the thread. Since CSLA is configured to use Windows authentication, it will simply use that value - assuming it was set by Windows itself.

Copyright (c) Marimer LLC