I'm attaching an NHibernate session to the operation context in my WCF webservice which allows me to access the session object during the processing of each operation (the service instance context is per call).
The service implements custom authentication using UserNamePasswordValidator but unfortunately prior to the request being authenticated the OperationContext.Current is always null (presumably by design).
My question is how should I set up the NHibernate session on the Validate(string userName, string password) method if I can't get the session via the OperationContext.Current? How are other peeps doing this?
Thanks in advance.
Use separate session in validator = create new one through session factory. There is no shared storage between security processing and operation processing by design. They should even run in different threads. You should follow this design and don't share session and loaded objects between security processing and operation processing.
Related
I'm currently working on a backend infrastructure and I could need some advice.
First, here is the current global architecture:
I have WCF services hosted in IIS
I have multiples databases hosted on SQL Server. One ClientData database per client and one global MasterDatabase.
MasterDatabase contains a mapping of credentials associated to a connection string. That database allows me to use the appropriate ClientData database (via Entity Framework) depending on the credentials provided.
I'm using Basic Auth over SSL.
Credentials verification are done in overridden method checkAccessCore() in my ServiceAuthorizationManager subclass. Inside that method, I fetch MasterDatabase, ensure credentials are correct (password are saved in DB using Bcrypt) and retrieve the connection string.
Once the connection string is retrieved, I create an instance of my class CustomIdentity that inherits from GenericIdentity. Using that instance I can then set the Thread.CurrentPrincipal property.
Each WCF service implementation retrieves the connection string from the CustomPrincipal in order to fetch data from the appropriate ClientData database.
My questions/thoughts are the following:
If I decide to use concurrency in my WCF services, how will I handle that due to the fact that CheckAccessCore is a method of a WCF extension that force concurrent operations to run sequentially?
http://support.microsoft.com/kb/KbView/2907010
This means that all my call will be enqueued and blocked at the checkAccessCore level.
Overriding checkAccessCore is the best way I found to intercept calls early in the call stack in order to verify user credentials.
Should I use a different way to transport the client connection string other than over the custom identity? Is it secure?
If I use concurrency, I guess the identity set into the CustomPrincipal will be overridden. If yes, how to handle that?
I've implemented custom logging logic for WCF service by using IDispatchMessageInspector.
I'm logging entire SOAP request/response in the database by utilizing both AfterReceiveRequest and BeforeSendReply.
I'm using claims-based authentication which works without any issues.
However, when I attempt to access Thread.CurrentPrincipal.Identity.Name or ClaimsPrincipal.Current.Identity.Name, I get empty string always (identity is not set, thus name is blank).
Is there a way to access the identity in any way from IDispatchMessageInspector?
Thank you!
If your claim-based authentication is working, you could add the user to your claimset.
You can access your ClaimSet in a static way:
ReadOnlyCollection<ClaimSet> claimSets = ServiceSecurityContext.Current.AuthorizationContext;`
The other possibility is adding a ServiceAuthorizationManager to your service, register it in your configuration and access your ClaimSet from this class.
Hope this helps
I've been trying several different ways in order to get a simple set of transactions to work for a simple WCF client/server situation. My WCF server has a class level declaration of the Entity Framework class for my database access and several methods to modify data and a method to SaveChanges. I'm using the Oracle Data Access (ODP.NET).
For instance I want to call a modification from the client and then a separate call to save the changes in the WCF service. It doesn't work. Basically, everything executes fine, but when the second call to save the changes is made, the WCF service no longer has the original context and therefore no changes are saved (and, consequently, the previous call that made the changes was automatically rolled back).
I'm utilizing Transaction scope around both operations in my client and executing Complete() after done. My WCF services have OperationContract's that use [TransactionFlow(TransactionFlowOption.Mandatory)] and those method implementations use [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]. Finally, my web config is configured with a wsHttpBinding that has the transactionFlow property set to True.
I'm having no luck. No matter what I try, when I try hitting the service for the follow-up save, the EF context is already renewed.
This has nothing to do with transaction. Transaction works on transactional resource but without calling SaveChanges in the first request there was no transactional resource active because EF context is not part of the transaction - the database is and the database is affected only when you call SaveChanges. To make this work you don't need distributed transactions. You need session-full service and store the EF context in the service instance. It a client uses the same client proxy instance to communicate with the service for all requests the communication will be handled by the same service instance = same EF context instance which will remember changes from previous calls.
IMHO this is very bad architecture. Simply don't use it. Expose specialized methods on WCF service which will do changes and save them. If you need to execute these methods in transaction with other transactional resources use the real distributed transaction.
this might be a reason. Since your are making an update in the different context. context doesn't know that the object is update to have say the context that the object is modified and then you call savechnages(). See if it helps
I have a WCF service which uses a custom authentication and authorization manager.
Each time a client makes a call the authentication manager looks for a message header and uses the information to identify the user. The user gets created as an IPrincipal and placed into ServiceSecurityContext.Current.AuthorizationContext.Properties["Principal"].
I noticed on subsequent calls, where the users is different, the old user info is in the Current context. My service is tagged as PerCall. I am stumped on why the context is not getting cleared for every call.
Or is OperationContext different lifetime from SecurityContext?
If so any ideas on how to achieve what I described above? Thanks for help.
It seems like I'm barking up the wrong tree when asking this question, this question and this question.
I need to authenticate users against a custom API (in COM), and I need to keep that custom API (the COM object) alive (for that user) for future WCF calls. During authentication against that custom API, I can get back a list of custom-defined roles. I'd also like to use these for authorization of the service methods.
Moreover, I need to be able to revoke the user's session remotely. This is triggered by an event raised by the COM API.
I've got a custom UserNamePasswordValidator, but it appears that this has no mechanism for correctly setting a custom principal, so it looks like I'm heading in the wrong direction.
How do I do these three things?
You can handle authentication completely in your service. Create service contract similar to:
[ServiceContract(SessionMode=SessionMode.Required)]
public interface IService
{
// All your operations marked with [OperationContract(IsInitiating=false, IsTerminating=false)]
// Two additional operations
[OperationContract(IsInitiating=true, IsTerminating=false)]
void Login(string user, string password);
[OperationContract(IsInitiating=false, IsTerminating=true)]
void Logout();
}
Service implementing this contract has to have PerSession instancing. Implement authentication in Login method and store COM object in local field. When new client want to use such service he has to first call the Login method. So all your instances will be properly authenticated and they will store their instance of COM object.
You can also register InstanceContext and COM object to some global class which will deal with forcibly killing service instance. This will probably require some research to make it work.
Make sure that you use some secure binding (encryption) because you will send user name and password as a plain text.